xref: /illumos-gate/usr/src/lib/libc/port/stdio/flush.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
30*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include "synonyms.h"
34*7c478bd9Sstevel@tonic-gate #include "mtlib.h"
35*7c478bd9Sstevel@tonic-gate #include "file64.h"
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #define	_iob	__iob
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
40*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
41*7c478bd9Sstevel@tonic-gate #include <stdio.h>
42*7c478bd9Sstevel@tonic-gate #include <thread.h>
43*7c478bd9Sstevel@tonic-gate #include <synch.h>
44*7c478bd9Sstevel@tonic-gate #include <unistd.h>
45*7c478bd9Sstevel@tonic-gate #include <string.h>
46*7c478bd9Sstevel@tonic-gate #include "stdiom.h"
47*7c478bd9Sstevel@tonic-gate #include <wchar.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
49*7c478bd9Sstevel@tonic-gate #include <stddef.h>
50*7c478bd9Sstevel@tonic-gate #include <errno.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #undef end
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #define	FILE_ARY_SZ	8 /* a nice size for FILE array & end_buffer_ptrs */
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /*
59*7c478bd9Sstevel@tonic-gate  * Macros to declare and loop over a fp or fp/xfp combo to
60*7c478bd9Sstevel@tonic-gate  * avoid some of the _LP64 ifdef hell.
61*7c478bd9Sstevel@tonic-gate  */
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate #define	FPDECL(fp)		FILE *fp
64*7c478bd9Sstevel@tonic-gate #define	FIRSTFP(lp, fp)		fp = lp->iobp
65*7c478bd9Sstevel@tonic-gate #define	NEXTFP(fp)		fp++
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #define	xFILE			FILE
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #else
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	FPDECL(fp)		FILE *fp; xFILE *x##fp
72*7c478bd9Sstevel@tonic-gate #define	FIRSTFP(lp, fp)		x##fp = lp->iobp; \
73*7c478bd9Sstevel@tonic-gate 				fp = x##fp ? &x##fp->_iob : &_iob[0]
74*7c478bd9Sstevel@tonic-gate #define	NEXTFP(fp)		(x##fp ? fp = &(++x##fp)->_iob : ++fp)
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /* The extended 32-bit file structure for use in link buffers */
77*7c478bd9Sstevel@tonic-gate typedef struct xFILE {
78*7c478bd9Sstevel@tonic-gate 	FILE			_iob;		/* must be first! */
79*7c478bd9Sstevel@tonic-gate 	struct xFILEdata	_xdat;
80*7c478bd9Sstevel@tonic-gate } xFILE;
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate #define	xmagic			_xdat._magic
83*7c478bd9Sstevel@tonic-gate #define	xend			_xdat._end
84*7c478bd9Sstevel@tonic-gate #define	xlock			_xdat._lock
85*7c478bd9Sstevel@tonic-gate #define	xstate			_xdat._state
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate #define	FILEx(fp)		((struct xFILE *)(uintptr_t)fp)
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate /*
90*7c478bd9Sstevel@tonic-gate  * The magic number stored is actually the pointer scrambled with
91*7c478bd9Sstevel@tonic-gate  * a magic number.  Pointers to data items live everywhere in memory
92*7c478bd9Sstevel@tonic-gate  * so we scramble the pointer in order to avoid accidental collisions.
93*7c478bd9Sstevel@tonic-gate  */
94*7c478bd9Sstevel@tonic-gate #define	XFILEMAGIC		0x63687367
95*7c478bd9Sstevel@tonic-gate #define	XMAGIC(xfp)		((uintptr_t)(xfp) ^ XFILEMAGIC)
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate #endif /* _LP64 */
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate struct _link_	/* manages a list of streams */
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	xFILE *iobp;		/* the array of (x)FILE's */
102*7c478bd9Sstevel@tonic-gate 				/* NULL for the __first_link in ILP32 */
103*7c478bd9Sstevel@tonic-gate 	int	niob;		/* length of the arrays */
104*7c478bd9Sstevel@tonic-gate 	struct _link_	*next;	/* next in the list */
105*7c478bd9Sstevel@tonic-gate };
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * With dynamic linking, iob may be in either the library or in the user's
109*7c478bd9Sstevel@tonic-gate  * a.out, so the run time linker fixes up the first entry in __first_link at
110*7c478bd9Sstevel@tonic-gate  * process startup time.
111*7c478bd9Sstevel@tonic-gate  *
112*7c478bd9Sstevel@tonic-gate  * In 32 bit processes, we don't have xFILE[FILE_ARY_SZ] but FILE[],
113*7c478bd9Sstevel@tonic-gate  * and _xftab[] instead; this is denoted by having iobp set to NULL in
114*7c478bd9Sstevel@tonic-gate  * 32 bit mode for the first link entry.
115*7c478bd9Sstevel@tonic-gate  */
116*7c478bd9Sstevel@tonic-gate struct _link_ __first_link =	/* first in linked list */
117*7c478bd9Sstevel@tonic-gate {
118*7c478bd9Sstevel@tonic-gate #if !defined(_LP64)
119*7c478bd9Sstevel@tonic-gate 	NULL,
120*7c478bd9Sstevel@tonic-gate #else
121*7c478bd9Sstevel@tonic-gate 	&_iob[0],
122*7c478bd9Sstevel@tonic-gate #endif
123*7c478bd9Sstevel@tonic-gate 	_NFILE,
124*7c478bd9Sstevel@tonic-gate 	NULL
125*7c478bd9Sstevel@tonic-gate };
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate  * Information cached to speed up searches.  We remember where we
129*7c478bd9Sstevel@tonic-gate  * last found a free FILE* and we remember whether we saw any fcloses
130*7c478bd9Sstevel@tonic-gate  * in between.  We also count the number of chunks we allocated, see
131*7c478bd9Sstevel@tonic-gate  * _findiop() for an explanation.
132*7c478bd9Sstevel@tonic-gate  * These variables are all protected by _first_link_lock.
133*7c478bd9Sstevel@tonic-gate  */
134*7c478bd9Sstevel@tonic-gate static struct _link_ *lastlink = NULL;
135*7c478bd9Sstevel@tonic-gate static int fcloses;
136*7c478bd9Sstevel@tonic-gate static int nchunks;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate static rwlock_t _first_link_lock = DEFAULTRWLOCK;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate static int _fflush_u_iops(void);
141*7c478bd9Sstevel@tonic-gate static FILE *getiop(FILE *, rmutex_t *, mbstate_t *);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate #define	GETIOP(fp, lk, mb)	{FILE *ret; \
144*7c478bd9Sstevel@tonic-gate 	if ((ret = getiop((fp), __threaded ? (lk) : NULL, (mb))) != NULL) { \
145*7c478bd9Sstevel@tonic-gate 		if (__threaded) \
146*7c478bd9Sstevel@tonic-gate 			(void) __rw_unlock(&_first_link_lock); \
147*7c478bd9Sstevel@tonic-gate 		return (ret); \
148*7c478bd9Sstevel@tonic-gate 	}; \
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate  * All functions that understand the linked list of iob's follow.
153*7c478bd9Sstevel@tonic-gate  */
154*7c478bd9Sstevel@tonic-gate #pragma weak _cleanup = __cleanup
155*7c478bd9Sstevel@tonic-gate void
156*7c478bd9Sstevel@tonic-gate __cleanup(void)		/* called at process end to flush ouput streams */
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate 	(void) fflush(NULL);
159*7c478bd9Sstevel@tonic-gate }
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate /*
162*7c478bd9Sstevel@tonic-gate  * For fork1-safety (see libc_prepare_atfork(), etc).
163*7c478bd9Sstevel@tonic-gate  */
164*7c478bd9Sstevel@tonic-gate void
165*7c478bd9Sstevel@tonic-gate stdio_locks()
166*7c478bd9Sstevel@tonic-gate {
167*7c478bd9Sstevel@tonic-gate 	(void) __rw_wrlock(&_first_link_lock);
168*7c478bd9Sstevel@tonic-gate 	/*
169*7c478bd9Sstevel@tonic-gate 	 * XXX: We should acquire all of the iob locks here.
170*7c478bd9Sstevel@tonic-gate 	 */
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate void
174*7c478bd9Sstevel@tonic-gate stdio_unlocks()
175*7c478bd9Sstevel@tonic-gate {
176*7c478bd9Sstevel@tonic-gate 	/*
177*7c478bd9Sstevel@tonic-gate 	 * XXX: We should release all of the iob locks here.
178*7c478bd9Sstevel@tonic-gate 	 */
179*7c478bd9Sstevel@tonic-gate 	(void) __rw_unlock(&_first_link_lock);
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate void
183*7c478bd9Sstevel@tonic-gate _flushlbf(void)		/* fflush() all line-buffered streams */
184*7c478bd9Sstevel@tonic-gate {
185*7c478bd9Sstevel@tonic-gate 	FPDECL(fp);
186*7c478bd9Sstevel@tonic-gate 	int i;
187*7c478bd9Sstevel@tonic-gate 	struct _link_ *lp;
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	if (__threaded)
190*7c478bd9Sstevel@tonic-gate 		(void) __rw_rdlock(&_first_link_lock);
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	lp = &__first_link;
193*7c478bd9Sstevel@tonic-gate 	do {
194*7c478bd9Sstevel@tonic-gate 		FIRSTFP(lp, fp);
195*7c478bd9Sstevel@tonic-gate 		for (i = lp->niob; --i >= 0; NEXTFP(fp)) {
196*7c478bd9Sstevel@tonic-gate 			if ((fp->_flag & (_IOLBF | _IOWRT)) ==
197*7c478bd9Sstevel@tonic-gate 			    (_IOLBF | _IOWRT))
198*7c478bd9Sstevel@tonic-gate 				(void) _fflush_u(fp);
199*7c478bd9Sstevel@tonic-gate 		}
200*7c478bd9Sstevel@tonic-gate 	} while ((lp = lp->next) != NULL);
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	if (__threaded)
203*7c478bd9Sstevel@tonic-gate 		(void) __rw_unlock(&_first_link_lock);
204*7c478bd9Sstevel@tonic-gate }
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate /* allocate an unused stream; NULL if cannot */
207*7c478bd9Sstevel@tonic-gate FILE *
208*7c478bd9Sstevel@tonic-gate _findiop(void)
209*7c478bd9Sstevel@tonic-gate {
210*7c478bd9Sstevel@tonic-gate 	struct _link_ *lp, **prev;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	/* used so there only needs to be one malloc() */
213*7c478bd9Sstevel@tonic-gate #ifdef _LP64
214*7c478bd9Sstevel@tonic-gate 	typedef	struct	{
215*7c478bd9Sstevel@tonic-gate 		struct _link_	hdr;
216*7c478bd9Sstevel@tonic-gate 		FILE	iob[FILE_ARY_SZ];
217*7c478bd9Sstevel@tonic-gate 	} Pkg;
218*7c478bd9Sstevel@tonic-gate #else
219*7c478bd9Sstevel@tonic-gate 	typedef union {
220*7c478bd9Sstevel@tonic-gate 		struct {				/* Normal */
221*7c478bd9Sstevel@tonic-gate 			struct _link_	hdr;
222*7c478bd9Sstevel@tonic-gate 			xFILE	iob[FILE_ARY_SZ];
223*7c478bd9Sstevel@tonic-gate 		} Pkgn;
224*7c478bd9Sstevel@tonic-gate 		struct {				/* Reversed */
225*7c478bd9Sstevel@tonic-gate 			xFILE	iob[FILE_ARY_SZ];
226*7c478bd9Sstevel@tonic-gate 			struct _link_	hdr;
227*7c478bd9Sstevel@tonic-gate 		} Pkgr;
228*7c478bd9Sstevel@tonic-gate 	} Pkg;
229*7c478bd9Sstevel@tonic-gate 	uintptr_t delta;
230*7c478bd9Sstevel@tonic-gate #endif
231*7c478bd9Sstevel@tonic-gate 	Pkg *pkgp;
232*7c478bd9Sstevel@tonic-gate 	struct _link_ *hdr;
233*7c478bd9Sstevel@tonic-gate 	FPDECL(fp);
234*7c478bd9Sstevel@tonic-gate 	int i;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	if (__threaded)
237*7c478bd9Sstevel@tonic-gate 		(void) __rw_wrlock(&_first_link_lock);
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	if (lastlink == NULL) {
240*7c478bd9Sstevel@tonic-gate rescan:
241*7c478bd9Sstevel@tonic-gate 		fcloses = 0;
242*7c478bd9Sstevel@tonic-gate 		lastlink = &__first_link;
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	lp = lastlink;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	/*
248*7c478bd9Sstevel@tonic-gate 	 * lock to make testing of fp->_flag == 0 and acquiring the fp atomic
249*7c478bd9Sstevel@tonic-gate 	 * and for allocation of new links
250*7c478bd9Sstevel@tonic-gate 	 * low contention expected on _findiop(), hence coarse locking.
251*7c478bd9Sstevel@tonic-gate 	 * for finer granularity, use fp->_lock for allocating an iop
252*7c478bd9Sstevel@tonic-gate 	 * and make the testing of lp->next and allocation of new link atomic
253*7c478bd9Sstevel@tonic-gate 	 * using lp->_lock
254*7c478bd9Sstevel@tonic-gate 	 */
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	do {
257*7c478bd9Sstevel@tonic-gate 		prev = &lp->next;
258*7c478bd9Sstevel@tonic-gate 		FIRSTFP(lp, fp);
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 		for (i = lp->niob; --i >= 0; NEXTFP(fp)) {
261*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
262*7c478bd9Sstevel@tonic-gate 			GETIOP(fp, &fp->_lock, &fp->_state);
263*7c478bd9Sstevel@tonic-gate #else
264*7c478bd9Sstevel@tonic-gate 			GETIOP(fp,
265*7c478bd9Sstevel@tonic-gate 			    xfp ? &xfp->xlock : &_xftab[IOPIND(fp)]._lock,
266*7c478bd9Sstevel@tonic-gate 			    xfp ? &xfp->xstate : &_xftab[IOPIND(fp)]._state);
267*7c478bd9Sstevel@tonic-gate #endif	/*	_LP64	*/
268*7c478bd9Sstevel@tonic-gate 		}
269*7c478bd9Sstevel@tonic-gate 	} while ((lastlink = lp = lp->next) != NULL);
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	/*
272*7c478bd9Sstevel@tonic-gate 	 * If there was a sufficient number of  fcloses since we last started
273*7c478bd9Sstevel@tonic-gate 	 * at __first_link, we rescan all fp's again.  We do not rescan for
274*7c478bd9Sstevel@tonic-gate 	 * all fcloses; that would simplify the algorithm but would make
275*7c478bd9Sstevel@tonic-gate 	 * search times near O(n) again.
276*7c478bd9Sstevel@tonic-gate 	 * Worst case behaviour would still be pretty bad (open a full set,
277*7c478bd9Sstevel@tonic-gate 	 * then continously opening and closing one FILE * gets you a full
278*7c478bd9Sstevel@tonic-gate 	 * scan each time).  That's why we over allocate 1 FILE for each
279*7c478bd9Sstevel@tonic-gate 	 * 32 chunks.  More over allocation is better; this is a nice
280*7c478bd9Sstevel@tonic-gate 	 * empirical value which doesn't cost a lot of memory, doesn't
281*7c478bd9Sstevel@tonic-gate 	 * overallocate until we reach 256 FILE *s and keeps the performance
282*7c478bd9Sstevel@tonic-gate 	 * pretty close to the optimum.
283*7c478bd9Sstevel@tonic-gate 	 */
284*7c478bd9Sstevel@tonic-gate 	if (fcloses > nchunks/32)
285*7c478bd9Sstevel@tonic-gate 		goto rescan;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/*
288*7c478bd9Sstevel@tonic-gate 	 * Need to allocate another and put it in the linked list.
289*7c478bd9Sstevel@tonic-gate 	 */
290*7c478bd9Sstevel@tonic-gate 	if ((pkgp = malloc(sizeof (Pkg))) == NULL) {
291*7c478bd9Sstevel@tonic-gate 		if (__threaded)
292*7c478bd9Sstevel@tonic-gate 			(void) __rw_unlock(&_first_link_lock);
293*7c478bd9Sstevel@tonic-gate 		return (NULL);
294*7c478bd9Sstevel@tonic-gate 	}
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	(void) memset(pkgp, 0, sizeof (Pkg));
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate #ifdef _LP64
299*7c478bd9Sstevel@tonic-gate 	hdr = &pkgp->hdr;
300*7c478bd9Sstevel@tonic-gate 	hdr->iobp = &pkgp->iob[0];
301*7c478bd9Sstevel@tonic-gate #else
302*7c478bd9Sstevel@tonic-gate 	/*
303*7c478bd9Sstevel@tonic-gate 	 * The problem with referencing a word after a FILE* is the possibility
304*7c478bd9Sstevel@tonic-gate 	 * of a SIGSEGV if a non-stdio issue FILE structure ends on a page
305*7c478bd9Sstevel@tonic-gate 	 * boundary.  We run this check so we never need to run an expensive
306*7c478bd9Sstevel@tonic-gate 	 * check like mincore() in order to know whether it is
307*7c478bd9Sstevel@tonic-gate 	 * safe to dereference ((xFILE*)fp)->xmagic.
308*7c478bd9Sstevel@tonic-gate 	 * We allocate the block with two alternative layouts; if one
309*7c478bd9Sstevel@tonic-gate 	 * layout is not properly aligned for our purposes, the other layout
310*7c478bd9Sstevel@tonic-gate 	 * will be because the size of _link_ is small compared to
311*7c478bd9Sstevel@tonic-gate 	 * sizeof (xFILE).
312*7c478bd9Sstevel@tonic-gate 	 * The check performed is this:
313*7c478bd9Sstevel@tonic-gate 	 *	If the distance from pkgp to the end of the page is
314*7c478bd9Sstevel@tonic-gate 	 *	less than the the offset of the last xmagic field in the
315*7c478bd9Sstevel@tonic-gate 	 *	xFILE structure, (the 0x1000 boundary is inside our just
316*7c478bd9Sstevel@tonic-gate 	 *	allocated structure) and the distance modulo the size of xFILE
317*7c478bd9Sstevel@tonic-gate 	 *	is identical to the offset of the first xmagic in the
318*7c478bd9Sstevel@tonic-gate 	 *	structure (i.e., XXXXXX000 points to an xmagic field),
319*7c478bd9Sstevel@tonic-gate 	 *	we need to use the reverse structure.
320*7c478bd9Sstevel@tonic-gate 	 */
321*7c478bd9Sstevel@tonic-gate 	if ((delta = 0x1000 - ((uintptr_t)pkgp & 0xfff)) <=
322*7c478bd9Sstevel@tonic-gate 				offsetof(Pkg, Pkgn.iob[FILE_ARY_SZ-1].xmagic) &&
323*7c478bd9Sstevel@tonic-gate 	    delta % sizeof (struct xFILE) ==
324*7c478bd9Sstevel@tonic-gate 		    offsetof(Pkg, Pkgn.iob[0].xmagic)) {
325*7c478bd9Sstevel@tonic-gate 		/* Use reversed structure */
326*7c478bd9Sstevel@tonic-gate 		hdr = &pkgp->Pkgr.hdr;
327*7c478bd9Sstevel@tonic-gate 		hdr->iobp = &pkgp->Pkgr.iob[0];
328*7c478bd9Sstevel@tonic-gate 	} else {
329*7c478bd9Sstevel@tonic-gate 		/* Use normal structure */
330*7c478bd9Sstevel@tonic-gate 		hdr = &pkgp->Pkgn.hdr;
331*7c478bd9Sstevel@tonic-gate 		hdr->iobp = &pkgp->Pkgn.iob[0];
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate #endif /* _LP64 */
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	hdr->niob = FILE_ARY_SZ;
336*7c478bd9Sstevel@tonic-gate 	nchunks++;
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
339*7c478bd9Sstevel@tonic-gate 	fp = hdr->iobp;
340*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FILE_ARY_SZ; i++)
341*7c478bd9Sstevel@tonic-gate 		_private_mutex_init(&fp[i]._lock,
342*7c478bd9Sstevel@tonic-gate 			USYNC_THREAD|LOCK_RECURSIVE, NULL);
343*7c478bd9Sstevel@tonic-gate #else
344*7c478bd9Sstevel@tonic-gate 	xfp = hdr->iobp;
345*7c478bd9Sstevel@tonic-gate 	fp = &xfp->_iob;
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FILE_ARY_SZ; i++) {
348*7c478bd9Sstevel@tonic-gate 		xfp[i].xmagic = XMAGIC(&xfp[i]);
349*7c478bd9Sstevel@tonic-gate 		_private_mutex_init(&xfp[i].xlock,
350*7c478bd9Sstevel@tonic-gate 			USYNC_THREAD|LOCK_RECURSIVE, NULL);
351*7c478bd9Sstevel@tonic-gate 	}
352*7c478bd9Sstevel@tonic-gate #endif	/*	_LP64	*/
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	lastlink = *prev = hdr;
355*7c478bd9Sstevel@tonic-gate 	fp->_ptr = 0;
356*7c478bd9Sstevel@tonic-gate 	fp->_base = 0;
357*7c478bd9Sstevel@tonic-gate 	fp->_flag = 0377; /* claim the fp by setting low 8 bits */
358*7c478bd9Sstevel@tonic-gate 	if (__threaded)
359*7c478bd9Sstevel@tonic-gate 		(void) __rw_unlock(&_first_link_lock);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	return (fp);
362*7c478bd9Sstevel@tonic-gate }
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate static void
365*7c478bd9Sstevel@tonic-gate isseekable(FILE *iop)
366*7c478bd9Sstevel@tonic-gate {
367*7c478bd9Sstevel@tonic-gate 	struct stat64 fstatbuf;
368*7c478bd9Sstevel@tonic-gate 	int save_errno;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	save_errno = errno;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	if (fstat64(iop->_file, &fstatbuf) != 0) {
373*7c478bd9Sstevel@tonic-gate 		/*
374*7c478bd9Sstevel@tonic-gate 		 * when we don't know what it is we'll
375*7c478bd9Sstevel@tonic-gate 		 * do the old behaviour and flush
376*7c478bd9Sstevel@tonic-gate 		 * the stream
377*7c478bd9Sstevel@tonic-gate 		 */
378*7c478bd9Sstevel@tonic-gate 		SET_SEEKABLE(iop);
379*7c478bd9Sstevel@tonic-gate 		errno = save_errno;
380*7c478bd9Sstevel@tonic-gate 		return;
381*7c478bd9Sstevel@tonic-gate 	}
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	/*
384*7c478bd9Sstevel@tonic-gate 	 * check for what is non-SEEKABLE
385*7c478bd9Sstevel@tonic-gate 	 * otherwise assume it's SEEKABLE so we get the old
386*7c478bd9Sstevel@tonic-gate 	 * behaviour and flush the stream
387*7c478bd9Sstevel@tonic-gate 	 */
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	if (S_ISFIFO(fstatbuf.st_mode) || S_ISCHR(fstatbuf.st_mode) ||
390*7c478bd9Sstevel@tonic-gate 	    S_ISSOCK(fstatbuf.st_mode) || S_ISDOOR(fstatbuf.st_mode)) {
391*7c478bd9Sstevel@tonic-gate 		CLEAR_SEEKABLE(iop);
392*7c478bd9Sstevel@tonic-gate 	} else {
393*7c478bd9Sstevel@tonic-gate 		SET_SEEKABLE(iop);
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	errno = save_errno;
397*7c478bd9Sstevel@tonic-gate }
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate #ifdef	_LP64
400*7c478bd9Sstevel@tonic-gate void
401*7c478bd9Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end)	/* set the end pointer for this iop */
402*7c478bd9Sstevel@tonic-gate {
403*7c478bd9Sstevel@tonic-gate 	iop->_end = end;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	isseekable(iop);
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate #undef _realbufend
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate Uchar *
411*7c478bd9Sstevel@tonic-gate _realbufend(FILE *iop)		/* get the end pointer for this iop */
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate 	return (iop->_end);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate #else /* _LP64 */
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate /*
419*7c478bd9Sstevel@tonic-gate  * Awkward functions not needed for the sane 64 bit environment.
420*7c478bd9Sstevel@tonic-gate  */
421*7c478bd9Sstevel@tonic-gate /*
422*7c478bd9Sstevel@tonic-gate  * xmagic must not be aligned on a 4K boundary. We guarantee this in
423*7c478bd9Sstevel@tonic-gate  * _findiop().
424*7c478bd9Sstevel@tonic-gate  */
425*7c478bd9Sstevel@tonic-gate #define	VALIDXFILE(xfp) \
426*7c478bd9Sstevel@tonic-gate 	(((uintptr_t)&(xfp)->xmagic & 0xfff) && \
427*7c478bd9Sstevel@tonic-gate 	    (xfp)->xmagic == XMAGIC(FILEx(xfp)))
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate static struct xFILEdata *
430*7c478bd9Sstevel@tonic-gate getxfdat(FILE *iop)
431*7c478bd9Sstevel@tonic-gate {
432*7c478bd9Sstevel@tonic-gate 	if (STDIOP(iop))
433*7c478bd9Sstevel@tonic-gate 		return (&_xftab[IOPIND(iop)]);
434*7c478bd9Sstevel@tonic-gate 	else if (VALIDXFILE(FILEx(iop)))
435*7c478bd9Sstevel@tonic-gate 		return (&FILEx(iop)->_xdat);
436*7c478bd9Sstevel@tonic-gate 	else
437*7c478bd9Sstevel@tonic-gate 		return (NULL);
438*7c478bd9Sstevel@tonic-gate }
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate void
441*7c478bd9Sstevel@tonic-gate _setbufend(FILE *iop, Uchar *end)	/* set the end pointer for this iop */
442*7c478bd9Sstevel@tonic-gate {
443*7c478bd9Sstevel@tonic-gate 	struct xFILEdata *dat = getxfdat(iop);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	if (dat != NULL)
446*7c478bd9Sstevel@tonic-gate 		dat->_end = end;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	isseekable(iop);
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	/*
451*7c478bd9Sstevel@tonic-gate 	 * For binary compatibility with user programs using the
452*7c478bd9Sstevel@tonic-gate 	 * old _bufend macro.  This is *so* broken, fileno()
453*7c478bd9Sstevel@tonic-gate 	 * is not the proper index.
454*7c478bd9Sstevel@tonic-gate 	 */
455*7c478bd9Sstevel@tonic-gate 	if (iop->_file < _NFILE)
456*7c478bd9Sstevel@tonic-gate 		_bufendtab[iop->_file] = end;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate }
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate Uchar *
461*7c478bd9Sstevel@tonic-gate _realbufend(FILE *iop)		/* get the end pointer for this iop */
462*7c478bd9Sstevel@tonic-gate {
463*7c478bd9Sstevel@tonic-gate 	struct xFILEdata *dat = getxfdat(iop);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	if (dat != NULL)
466*7c478bd9Sstevel@tonic-gate 		return (dat->_end);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	return (NULL);
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate /*
472*7c478bd9Sstevel@tonic-gate  * _reallock() is invoked in each stdio call through the IOB_LCK() macro,
473*7c478bd9Sstevel@tonic-gate  * it is therefor extremely performance sensitive.  We get better performance
474*7c478bd9Sstevel@tonic-gate  * by inlining the STDIOP check in IOB_LCK and inlining a custom version
475*7c478bd9Sstevel@tonic-gate  * of getfxdat() here.
476*7c478bd9Sstevel@tonic-gate  */
477*7c478bd9Sstevel@tonic-gate rmutex_t *
478*7c478bd9Sstevel@tonic-gate _reallock(FILE *iop)
479*7c478bd9Sstevel@tonic-gate {
480*7c478bd9Sstevel@tonic-gate 	if (VALIDXFILE(FILEx(iop)))
481*7c478bd9Sstevel@tonic-gate 		return (&FILEx(iop)->xlock);
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	return (NULL);
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate #endif	/*	_LP64	*/
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate /* make sure _cnt, _ptr are correct */
489*7c478bd9Sstevel@tonic-gate void
490*7c478bd9Sstevel@tonic-gate _bufsync(FILE *iop, Uchar *bufend)
491*7c478bd9Sstevel@tonic-gate {
492*7c478bd9Sstevel@tonic-gate 	ssize_t spaceleft;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	spaceleft = bufend - iop->_ptr;
495*7c478bd9Sstevel@tonic-gate 	if (bufend < iop->_ptr) {
496*7c478bd9Sstevel@tonic-gate 		iop->_ptr = bufend;
497*7c478bd9Sstevel@tonic-gate 		iop->_cnt = 0;
498*7c478bd9Sstevel@tonic-gate 	} else if (spaceleft < iop->_cnt)
499*7c478bd9Sstevel@tonic-gate 		iop->_cnt = spaceleft;
500*7c478bd9Sstevel@tonic-gate }
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate /* really write out current buffer contents */
503*7c478bd9Sstevel@tonic-gate int
504*7c478bd9Sstevel@tonic-gate _xflsbuf(FILE *iop)
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	ssize_t n;
507*7c478bd9Sstevel@tonic-gate 	Uchar *base = iop->_base;
508*7c478bd9Sstevel@tonic-gate 	Uchar *bufend;
509*7c478bd9Sstevel@tonic-gate 	ssize_t num_wrote;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	/*
512*7c478bd9Sstevel@tonic-gate 	 * Hopefully, be stable with respect to interrupts...
513*7c478bd9Sstevel@tonic-gate 	 */
514*7c478bd9Sstevel@tonic-gate 	n = iop->_ptr - base;
515*7c478bd9Sstevel@tonic-gate 	iop->_ptr = base;
516*7c478bd9Sstevel@tonic-gate 	bufend = _bufend(iop);
517*7c478bd9Sstevel@tonic-gate 	if (iop->_flag & (_IOLBF | _IONBF))
518*7c478bd9Sstevel@tonic-gate 		iop->_cnt = 0;		/* always go to a flush */
519*7c478bd9Sstevel@tonic-gate 	else
520*7c478bd9Sstevel@tonic-gate 		iop->_cnt = bufend - base;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if (_needsync(iop, bufend))	/* recover from interrupts */
523*7c478bd9Sstevel@tonic-gate 		_bufsync(iop, bufend);
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	if (n > 0) {
526*7c478bd9Sstevel@tonic-gate 		while ((num_wrote =
527*7c478bd9Sstevel@tonic-gate 			write(iop->_file, base, (size_t)n)) != n) {
528*7c478bd9Sstevel@tonic-gate 			if (num_wrote <= 0) {
529*7c478bd9Sstevel@tonic-gate 				iop->_flag |= _IOERR;
530*7c478bd9Sstevel@tonic-gate 				return (EOF);
531*7c478bd9Sstevel@tonic-gate 			}
532*7c478bd9Sstevel@tonic-gate 			n -= num_wrote;
533*7c478bd9Sstevel@tonic-gate 			base += num_wrote;
534*7c478bd9Sstevel@tonic-gate 		}
535*7c478bd9Sstevel@tonic-gate 	}
536*7c478bd9Sstevel@tonic-gate 	return (0);
537*7c478bd9Sstevel@tonic-gate }
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate /* flush (write) buffer */
540*7c478bd9Sstevel@tonic-gate int
541*7c478bd9Sstevel@tonic-gate fflush(FILE *iop)
542*7c478bd9Sstevel@tonic-gate {
543*7c478bd9Sstevel@tonic-gate 	int res;
544*7c478bd9Sstevel@tonic-gate 	rmutex_t *lk;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	if (iop) {
547*7c478bd9Sstevel@tonic-gate 		FLOCKFILE(lk, iop);
548*7c478bd9Sstevel@tonic-gate 		res = _fflush_u(iop);
549*7c478bd9Sstevel@tonic-gate 		FUNLOCKFILE(lk);
550*7c478bd9Sstevel@tonic-gate 	} else {
551*7c478bd9Sstevel@tonic-gate 		res = _fflush_u_iops();		/* flush all iops */
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate 	return (res);
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate static int
557*7c478bd9Sstevel@tonic-gate _fflush_u_iops(void)		/* flush all buffers */
558*7c478bd9Sstevel@tonic-gate {
559*7c478bd9Sstevel@tonic-gate 	FPDECL(iop);
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	int i;
562*7c478bd9Sstevel@tonic-gate 	struct _link_ *lp;
563*7c478bd9Sstevel@tonic-gate 	int res = 0;
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	if (__threaded)
566*7c478bd9Sstevel@tonic-gate 		(void) __rw_rdlock(&_first_link_lock);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	lp = &__first_link;
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	do {
571*7c478bd9Sstevel@tonic-gate 		/*
572*7c478bd9Sstevel@tonic-gate 		 * Don't grab the locks for these file pointers
573*7c478bd9Sstevel@tonic-gate 		 * since they are supposed to be flushed anyway
574*7c478bd9Sstevel@tonic-gate 		 * It could also be the case in which the 2nd
575*7c478bd9Sstevel@tonic-gate 		 * portion (base and lock) are not initialized
576*7c478bd9Sstevel@tonic-gate 		 */
577*7c478bd9Sstevel@tonic-gate 		FIRSTFP(lp, iop);
578*7c478bd9Sstevel@tonic-gate 		for (i = lp->niob; --i >= 0; NEXTFP(iop)) {
579*7c478bd9Sstevel@tonic-gate 		    if (!(iop->_flag & _IONBF)) {
580*7c478bd9Sstevel@tonic-gate 			/*
581*7c478bd9Sstevel@tonic-gate 			 * don't need to worry about the _IORW case
582*7c478bd9Sstevel@tonic-gate 			 * since the iop will also marked with _IOREAD
583*7c478bd9Sstevel@tonic-gate 			 * or _IOWRT whichever we are really doing
584*7c478bd9Sstevel@tonic-gate 			 */
585*7c478bd9Sstevel@tonic-gate 			if (iop->_flag & _IOWRT) {    /* flush write buffers */
586*7c478bd9Sstevel@tonic-gate 			    res |= _fflush_u(iop);
587*7c478bd9Sstevel@tonic-gate 			} else if (iop->_flag & _IOREAD) {
588*7c478bd9Sstevel@tonic-gate 				/*
589*7c478bd9Sstevel@tonic-gate 				 * flush seekable read buffers
590*7c478bd9Sstevel@tonic-gate 				 * don't flush non-seekable read buffers
591*7c478bd9Sstevel@tonic-gate 				 */
592*7c478bd9Sstevel@tonic-gate 			    if (GET_SEEKABLE(iop)) {
593*7c478bd9Sstevel@tonic-gate 				res |= _fflush_u(iop);
594*7c478bd9Sstevel@tonic-gate 			    }
595*7c478bd9Sstevel@tonic-gate 			}
596*7c478bd9Sstevel@tonic-gate 		    }
597*7c478bd9Sstevel@tonic-gate 		}
598*7c478bd9Sstevel@tonic-gate 	} while ((lp = lp->next) != NULL);
599*7c478bd9Sstevel@tonic-gate 	if (__threaded)
600*7c478bd9Sstevel@tonic-gate 		(void) __rw_unlock(&_first_link_lock);
601*7c478bd9Sstevel@tonic-gate 	return (res);
602*7c478bd9Sstevel@tonic-gate }
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate /* flush buffer */
605*7c478bd9Sstevel@tonic-gate int
606*7c478bd9Sstevel@tonic-gate _fflush_u(FILE *iop)
607*7c478bd9Sstevel@tonic-gate {
608*7c478bd9Sstevel@tonic-gate 	int res = 0;
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	/* this portion is always assumed locked */
611*7c478bd9Sstevel@tonic-gate 	if (!(iop->_flag & _IOWRT)) {
612*7c478bd9Sstevel@tonic-gate 		(void) lseek64(iop->_file, -iop->_cnt, SEEK_CUR);
613*7c478bd9Sstevel@tonic-gate 		iop->_cnt = 0;
614*7c478bd9Sstevel@tonic-gate 		/* needed for ungetc & multibyte pushbacks */
615*7c478bd9Sstevel@tonic-gate 		iop->_ptr = iop->_base;
616*7c478bd9Sstevel@tonic-gate 		if (iop->_flag & _IORW) {
617*7c478bd9Sstevel@tonic-gate 			iop->_flag &= ~_IOREAD;
618*7c478bd9Sstevel@tonic-gate 		}
619*7c478bd9Sstevel@tonic-gate 		return (0);
620*7c478bd9Sstevel@tonic-gate 	}
621*7c478bd9Sstevel@tonic-gate 	if (iop->_base != NULL && iop->_ptr > iop->_base) {
622*7c478bd9Sstevel@tonic-gate 		res = _xflsbuf(iop);
623*7c478bd9Sstevel@tonic-gate 	}
624*7c478bd9Sstevel@tonic-gate 	if (iop->_flag & _IORW) {
625*7c478bd9Sstevel@tonic-gate 		iop->_flag &= ~_IOWRT;
626*7c478bd9Sstevel@tonic-gate 		iop->_cnt = 0;
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate 	return (res);
629*7c478bd9Sstevel@tonic-gate }
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate /* flush buffer and close stream */
632*7c478bd9Sstevel@tonic-gate int
633*7c478bd9Sstevel@tonic-gate fclose(FILE *iop)
634*7c478bd9Sstevel@tonic-gate {
635*7c478bd9Sstevel@tonic-gate 	int res = 0;
636*7c478bd9Sstevel@tonic-gate 	rmutex_t *lk;
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	if (iop == NULL) {
639*7c478bd9Sstevel@tonic-gate 		return (EOF);		/* avoid passing zero to FLOCKFILE */
640*7c478bd9Sstevel@tonic-gate 	}
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	FLOCKFILE(lk, iop);
643*7c478bd9Sstevel@tonic-gate 	if (iop->_flag == 0) {
644*7c478bd9Sstevel@tonic-gate 		FUNLOCKFILE(lk);
645*7c478bd9Sstevel@tonic-gate 		return (EOF);
646*7c478bd9Sstevel@tonic-gate 	}
647*7c478bd9Sstevel@tonic-gate 	/* Is not unbuffered and opened for read and/or write ? */
648*7c478bd9Sstevel@tonic-gate 	if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW)))
649*7c478bd9Sstevel@tonic-gate 		res = _fflush_u(iop);
650*7c478bd9Sstevel@tonic-gate 	if (close(iop->_file) < 0)
651*7c478bd9Sstevel@tonic-gate 		res = EOF;
652*7c478bd9Sstevel@tonic-gate 	if (iop->_flag & _IOMYBUF) {
653*7c478bd9Sstevel@tonic-gate 		(void) free((char *)iop->_base - PUSHBACK);
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 	iop->_base = NULL;
656*7c478bd9Sstevel@tonic-gate 	iop->_ptr = NULL;
657*7c478bd9Sstevel@tonic-gate 	iop->_cnt = 0;
658*7c478bd9Sstevel@tonic-gate 	iop->_flag = 0;			/* marks it as available */
659*7c478bd9Sstevel@tonic-gate 	FUNLOCKFILE(lk);
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	if (__threaded)
662*7c478bd9Sstevel@tonic-gate 		(void) __rw_wrlock(&_first_link_lock);
663*7c478bd9Sstevel@tonic-gate 	fcloses++;
664*7c478bd9Sstevel@tonic-gate 	if (__threaded)
665*7c478bd9Sstevel@tonic-gate 		(void) __rw_unlock(&_first_link_lock);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	return (res);
668*7c478bd9Sstevel@tonic-gate }
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate /* flush buffer, close fd but keep the stream used by freopen() */
671*7c478bd9Sstevel@tonic-gate int
672*7c478bd9Sstevel@tonic-gate close_fd(FILE *iop)
673*7c478bd9Sstevel@tonic-gate {
674*7c478bd9Sstevel@tonic-gate 	int res = 0;
675*7c478bd9Sstevel@tonic-gate 	mbstate_t *mb;
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	if (iop == NULL || iop->_flag == 0)
678*7c478bd9Sstevel@tonic-gate 		return (EOF);
679*7c478bd9Sstevel@tonic-gate 	/* Is not unbuffered and opened for read and/or write ? */
680*7c478bd9Sstevel@tonic-gate 	if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW)))
681*7c478bd9Sstevel@tonic-gate 		res = _fflush_u(iop);
682*7c478bd9Sstevel@tonic-gate 	if (close(iop->_file) < 0)
683*7c478bd9Sstevel@tonic-gate 		res = EOF;
684*7c478bd9Sstevel@tonic-gate 	if (iop->_flag & _IOMYBUF) {
685*7c478bd9Sstevel@tonic-gate 		(void) free((char *)iop->_base - PUSHBACK);
686*7c478bd9Sstevel@tonic-gate 	}
687*7c478bd9Sstevel@tonic-gate 	iop->_base = NULL;
688*7c478bd9Sstevel@tonic-gate 	iop->_ptr = NULL;
689*7c478bd9Sstevel@tonic-gate 	mb = _getmbstate(iop);
690*7c478bd9Sstevel@tonic-gate 	if (mb != NULL)
691*7c478bd9Sstevel@tonic-gate 		(void) memset(mb, 0, sizeof (mbstate_t));
692*7c478bd9Sstevel@tonic-gate 	iop->_cnt = 0;
693*7c478bd9Sstevel@tonic-gate 	_setorientation(iop, _NO_MODE);
694*7c478bd9Sstevel@tonic-gate 	return (res);
695*7c478bd9Sstevel@tonic-gate }
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate static FILE *
698*7c478bd9Sstevel@tonic-gate getiop(FILE *fp, rmutex_t *lk, mbstate_t *mb)
699*7c478bd9Sstevel@tonic-gate {
700*7c478bd9Sstevel@tonic-gate 	if (lk != NULL && rmutex_trylock(lk))
701*7c478bd9Sstevel@tonic-gate 		return (NULL);	/* locked: fp in use */
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	if (fp->_flag == 0) {	/* unused */
704*7c478bd9Sstevel@tonic-gate #ifndef	_LP64
705*7c478bd9Sstevel@tonic-gate 		fp->__orientation = 0;
706*7c478bd9Sstevel@tonic-gate #endif /* _LP64 */
707*7c478bd9Sstevel@tonic-gate 		fp->_cnt = 0;
708*7c478bd9Sstevel@tonic-gate 		fp->_ptr = NULL;
709*7c478bd9Sstevel@tonic-gate 		fp->_base = NULL;
710*7c478bd9Sstevel@tonic-gate 		fp->_flag = 0377;	/* claim the fp by setting low 8 bits */
711*7c478bd9Sstevel@tonic-gate 		(void) memset(mb, 0, sizeof (mbstate_t));
712*7c478bd9Sstevel@tonic-gate 		FUNLOCKFILE(lk);
713*7c478bd9Sstevel@tonic-gate 		return (fp);
714*7c478bd9Sstevel@tonic-gate 	}
715*7c478bd9Sstevel@tonic-gate 	FUNLOCKFILE(lk);
716*7c478bd9Sstevel@tonic-gate 	return (NULL);
717*7c478bd9Sstevel@tonic-gate }
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate #ifndef	_LP64
720*7c478bd9Sstevel@tonic-gate /*
721*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:
722*7c478bd9Sstevel@tonic-gate  * This function gets the pointer to the mbstate_t structure associated
723*7c478bd9Sstevel@tonic-gate  * with the specified iop.
724*7c478bd9Sstevel@tonic-gate  *
725*7c478bd9Sstevel@tonic-gate  * RETURNS:
726*7c478bd9Sstevel@tonic-gate  * If the associated mbstate_t found, the pointer to the mbstate_t is
727*7c478bd9Sstevel@tonic-gate  * returned.  Otherwise, NULL is returned.
728*7c478bd9Sstevel@tonic-gate  */
729*7c478bd9Sstevel@tonic-gate mbstate_t *
730*7c478bd9Sstevel@tonic-gate _getmbstate(FILE *iop)
731*7c478bd9Sstevel@tonic-gate {
732*7c478bd9Sstevel@tonic-gate 	struct xFILEdata *dat = getxfdat(iop);
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	if (dat != NULL)
735*7c478bd9Sstevel@tonic-gate 		return (&dat->_state);
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	return (NULL);
738*7c478bd9Sstevel@tonic-gate }
739*7c478bd9Sstevel@tonic-gate #endif
740