findfp.c.patch   [plain text]


--- findfp.c.orig	2009-02-15 03:11:22.000000000 -0800
+++ findfp.c	2009-02-15 18:45:19.000000000 -0800
@@ -46,7 +46,10 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/f
 #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"
@@ -62,12 +65,19 @@ int	__sdidinit;
 	 {0}, __sFX + file}
   /*	 p r w flags file _bf z  cookie      close    read    seek    write */
   /*     _ub _extra */
+#define	__sFXInit	{0, PTHREAD_MUTEX_INITIALIZER}
+  /* set counted */
+#define	__sFXInit3	{0, PTHREAD_MUTEX_INITIALIZER, 0, 0, 0, 1}
 				/* the usual - (stdin + stdout + stderr) */
+
+static int __scounted;		/* streams counted against STREAM_MAX */
+static int __stream_max;
+
 static FILE usual[FOPEN_MAX - 3];
 static struct __sFILEX usual_extra[FOPEN_MAX - 3];
 static struct glue uglue = { NULL, FOPEN_MAX - 3, usual };
 
-static struct __sFILEX __sFX[3];
+static struct __sFILEX __sFX[3] = {__sFXInit3, __sFXInit3, __sFXInit3};
 
 /*
  * We can't make this 'static' until 6.0-current due to binary
@@ -113,7 +123,7 @@ moreglue(n)
 {
 	struct glue *g;
 	static FILE empty;
-	static struct __sFILEX emptyx;
+	static struct __sFILEX emptyx = __sFXInit;
 	FILE *p;
 	struct __sFILEX *fx;
 
@@ -139,7 +149,7 @@ moreglue(n)
  * Find a free FILE for fopen et al.
  */
 FILE *
-__sfp()
+__sfp(int count)
 {
 	FILE	*fp;
 	int	n;
@@ -147,6 +157,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.
 	 */
@@ -179,12 +198,27 @@ found:
 	fp->_lb._base = NULL;	/* no line buffer */
 	fp->_lb._size = 0;
 /*	fp->_lock = NULL; */	/* once set always set (reused) */
+	fp->_extra->fl_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
 	fp->_extra->orientation = 0;
+	fp->_extra->counted = count ? 1 : 0;
 	memset(&fp->_extra->mbstate, 0, sizeof(mbstate_t));
 	return (fp);
 }
 
 /*
+ * Mark as free and update count as needed
+ */
+__private_extern__ void
+__sfprelease(FILE *fp)
+{
+	if (fp->_extra->counted) {
+		OSAtomicDecrement32(&__scounted);
+		fp->_extra->counted = 0;
+	}
+	fp->_flags = 0;
+}
+
+/*
  * XXX.  Force immediate allocation of internal memory.  Not used by stdio,
  * but documented historically for certain applications.  Bad applications.
  */
@@ -244,6 +278,8 @@ __sinit()
 		/* Make sure we clean up on exit. */
 		__cleanup = _cleanup;		/* conservative */
 		__sdidinit = 1;
+		__stream_max = sysconf(_SC_STREAM_MAX);
+		__scounted = 3;			/* std{in,out,err} already exists */
 	}
 	THREAD_UNLOCK();
 }