[PATCH] libc FILE locking

David Xu davidxu at t2t2.com
Fri May 6 22:50:06 PDT 2005


Please test attached patch, I want to make sure it does not break
anything.
David Xu

Index: include/stdio.h
===================================================================
RCS file: /cvs/src/include/stdio.h,v
retrieving revision 1.6
diff -u -u -r1.6 stdio.h
--- include/stdio.h	31 Jan 2005 22:28:58 -0000	1.6
+++ include/stdio.h	7 May 2005 05:43:43 -0000
@@ -118,7 +118,7 @@
 
 	/* separate buffer for long sequences of ungetc() */
 	struct	__sbuf _ub;	/* ungetc buffer */
-	unsigned char *_up;	/* saved _p when _p is doing ungetc data */
+	struct  __sFILEX *_extra;
 	int	_ur;		/* saved _r when _r is counting ungetc data */
 
 	/* tricks to meet minimum requirements even when malloc() fails */
Index: lib/libc/gen/_pthread_stubs.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/_pthread_stubs.c,v
retrieving revision 1.3
diff -u -u -r1.3 _pthread_stubs.c
--- lib/libc/gen/_pthread_stubs.c	26 Apr 2005 10:05:08 -0000	1.3
+++ lib/libc/gen/_pthread_stubs.c	7 May 2005 05:44:00 -0000
@@ -44,6 +44,12 @@
 int	_pthread_once_stub(pthread_once_t *, void (*)(void));
 int	_pthread_setspecific_stub(pthread_key_t, const void *);
 
+/* define a null pthread structure just to satisfy _pthread_self */
+struct pthread {
+};
+
+static struct pthread main_thread;
+
 /*
  * Weak symbols: All libc internal usage of these functions should
  * use the weak symbol versions (_pthread_XXX).  If libpthread is
@@ -66,6 +72,7 @@
 __weak_reference(_pthread_mutexattr_settype_stub,_pthread_mutexattr_settype);
 __weak_reference(_pthread_once_stub,_pthread_once);
 __weak_reference(_pthread_setspecific_stub,_pthread_setspecific);
+__weak_reference(_pthread_self_stub,_pthread_self);
 
 void *
 _pthread_getspecific_stub(pthread_key_t key __unused)
@@ -143,6 +150,11 @@
 	return (0);
 }
 
+struct pthread *
+_pthread_self_stub(void)
+{
+	return (&main_thread);
+}
 int
 _pthread_setspecific_stub(pthread_key_t key __unused,
 			  const void *value __unused)
Index: lib/libc/stdio/_flock_stub.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/_flock_stub.c,v
retrieving revision 1.6
diff -u -u -r1.6 _flock_stub.c
--- lib/libc/stdio/_flock_stub.c	2 Feb 2005 04:57:15 -0000	1.6
+++ lib/libc/stdio/_flock_stub.c	7 May 2005 05:44:08 -0000
@@ -34,7 +34,12 @@
  *
  */
 
+#include "namespace.h"
 #include <stdio.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "local.h"
 
 /* Don't build this in libc_r, just libc: */
 /*
@@ -55,11 +60,34 @@
 void	funlockfile(FILE *);
 
 /*
+ * We need to retain binary compatibility for a while.  So pretend
+ * that _lock is part of FILE * even though it is dereferenced off
+ * _extra now.  When we stop encoding the size of FILE into binaries
+ * this can be changed in stdio.h.  This will reduce the amount of
+ * code that has to change in the future (just remove this comment
+ * and #define).
+ */
+#define _lock _extra
+
+/*
  * This function is a stub for the _flockfile function in libpthread.
  */
 void
 _flockfile_stub(FILE *fp)
 {
+	pthread_t curthread = _pthread_self();
+
+	if (fp->_lock->fl_owner == curthread)
+		fp->_lock->fl_count++;
+	else {
+		/*
+		 * Make sure this mutex is treated as a private
+		 * internal mutex:
+		 */
+		_pthread_mutex_lock(&fp->_lock->fl_mutex);
+		fp->_lock->fl_owner = curthread;
+		fp->_lock->fl_count = 1;
+	}
 }
 
 /*
@@ -68,6 +96,7 @@
 void
 _flockfile_debug_stub(FILE *fp, char *fname, int lineno)
 {
+	_flockfile(fp);
 }
 
 /*
@@ -76,7 +105,22 @@
 int
 _ftrylockfile_stub(FILE *fp)
 {
-	return(0);
+	pthread_t curthread = _pthread_self();
+	int	ret = 0;
+
+	if (fp->_lock->fl_owner == curthread)
+		fp->_lock->fl_count++;
+	/*
+	 * Make sure this mutex is treated as a private
+	 * internal mutex:
+	 */
+	else if (_pthread_mutex_trylock(&fp->_lock->fl_mutex) == 0) {
+		fp->_lock->fl_owner = curthread;
+		fp->_lock->fl_count = 1;
+	}
+	else
+		ret = -1;
+	return (ret);
 }
 
 /*
@@ -85,4 +129,31 @@
 void
 _funlockfile_stub(FILE *fp)
 {
+	pthread_t	curthread = _pthread_self();
+
+	/*
+	 * Check if this file is owned by the current thread:
+	 */
+	if (fp->_lock->fl_owner == curthread) {
+		/*
+		 * Check if this thread has locked the FILE
+		 * more than once:
+		 */
+		if (fp->_lock->fl_count > 1)
+			/*
+			 * Decrement the count of the number of
+			 * times the running thread has locked this
+			 * file:
+			 */
+			fp->_lock->fl_count--;
+		else {
+			/*
+			 * The running thread will release the
+			 * lock now:
+			 */
+			fp->_lock->fl_count = 0;
+			fp->_lock->fl_owner = NULL;
+			_pthread_mutex_unlock(&fp->_lock->fl_mutex);
+		}
+	}
 }
Index: lib/libc/stdio/asprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/asprintf.c,v
retrieving revision 1.4
diff -u -u -r1.4 asprintf.c
--- lib/libc/stdio/asprintf.c	7 Jun 2004 17:59:42 -0000	1.4
+++ lib/libc/stdio/asprintf.c	7 May 2005 05:44:12 -0000
@@ -35,12 +35,15 @@
 #include <errno.h>
 #include <stdarg.h>
 
+#include "local.h"
+
 int
 asprintf(char **str, char const *fmt, ...)
 {
 	int ret;
 	va_list ap;
 	FILE f;
+	struct __sFILEX ext;
 
 	f._file = -1;
 	f._flags = __SWR | __SSTR | __SALC;
@@ -51,8 +54,10 @@
 		return (-1);
 	}
 	f._bf._size = f._w = 127;		/* Leave room for the NUL */
+	f._extra = &ext;
+	INITEXTRA(&f);
 	va_start(ap, fmt);
-	ret = vfprintf(&f, fmt, ap);
+	ret = __vfprintf(&f, fmt, ap);		/* Use unlocked __vfprintf */
 	va_end(ap);
 	if (ret < 0) {
 		free(f._bf._base);
Index: lib/libc/stdio/findfp.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/findfp.c,v
retrieving revision 1.6
diff -u -u -r1.6 findfp.c
--- lib/libc/stdio/findfp.c	31 Jan 2005 22:29:40 -0000	1.6
+++ lib/libc/stdio/findfp.c	7 May 2005 05:44:12 -0000
@@ -56,13 +56,18 @@
 #define	NDYNAMIC 10		/* add ten more whenever necessary */
 
 #define	std(flags, file) \
-	{0,0,0,flags,file,{0},0,__sF+file,__sclose,__sread,__sseek,__swrite}
+	{0,0,0,flags,file,{0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \
+	 {0}, __sFX + file}
 /*	 p r w flags file _bf z  cookie      close    read    seek    write */
+/*	_ub _extra */
 
 				/* 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 };
 
+static struct __sFILEX __sFX[3];
+
 FILE __sF[3] = {
 	std(__SRD, STDIN_FILENO),		/* stdin */
 	std(__SWR, STDOUT_FILENO),		/* stdout */
@@ -103,18 +108,26 @@
 moreglue(int n)
 {
 	struct glue *g;
-	FILE *p;
 	static FILE empty;
+	static struct __sFILEX emptyx;
+	FILE *p;
+	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);
 }
 
@@ -214,7 +227,17 @@
 void
 __sinit(void)
 {
-	/* make sure we clean up on exit */
-	__cleanup = _cleanup;		/* conservative */
-	__sdidinit = 1;
+	int	i;
+
+	THREAD_LOCK();
+	if (__sdidinit == 0) {
+		/* Set _extra for the usual suspects. */
+		for (i = 0; i < FOPEN_MAX - 3; i++)
+			usual[i]._extra = &usual_extra[i];
+
+		/* Make sure we clean up on exit. */
+		__cleanup = _cleanup;		/* conservative */
+		__sdidinit = 1;
+	}
+	THREAD_UNLOCK();
 }
Index: lib/libc/stdio/fseek.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/fseek.c,v
retrieving revision 1.6
diff -u -u -r1.6 fseek.c
--- lib/libc/stdio/fseek.c	31 Jan 2005 22:29:40 -0000	1.6
+++ lib/libc/stdio/fseek.c	7 May 2005 05:44:13 -0000
@@ -195,7 +195,7 @@
 	 */
 	if (HASUB(fp)) {
 		curoff += fp->_r;	/* kill off ungetc */
-		n = fp->_up - fp->_bf._base;
+		n = fp->_extra->_up - fp->_bf._base;
 		curoff -= n;
 		n += fp->_ur;
 	} else {
Index: lib/libc/stdio/local.h
===================================================================
RCS file: /cvs/src/lib/libc/stdio/local.h,v
retrieving revision 1.5
diff -u -u -r1.5 local.h
--- lib/libc/stdio/local.h	31 Jan 2005 22:29:40 -0000	1.5
+++ lib/libc/stdio/local.h	7 May 2005 05:44:13 -0000
@@ -40,6 +40,7 @@
  */
 
 #include <sys/types.h> /* for off_t */
+#include <pthread.h>
 
 #ifndef _MACHINE_STDINT_H_
 #include <machine/stdint.h>	/* __size_t */
@@ -65,9 +66,18 @@
 extern int	_fwalk (int (*)(FILE *));
 extern int	__swsetup (FILE *);
 extern int	__sflags (const char *, int *);
+extern int	__vfprintf(FILE *, const char *, __va_list);
 
 extern int	__sdidinit;
 
+/* hold a buncha junk that would grow the ABI */
+struct __sFILEX {
+	unsigned char	*_up;	/* saved _p when _p is doing ungetc data */
+	pthread_mutex_t	fl_mutex;	/* used for MT-safety */
+	pthread_t	fl_owner;	/* current owner */
+	int		fl_count;	/* recursive lock count */
+};
+
 /*
  * Return true iff the given FILE cannot be written now.
  */
@@ -94,3 +104,11 @@
 	free((char *)(fp)->_lb._base); \
 	(fp)->_lb._base = NULL; \
 }
+
+#define	INITEXTRA(fp) { \
+	(fp)->_extra->_up = NULL; \
+	(fp)->_extra->fl_mutex = PTHREAD_MUTEX_INITIALIZER; \
+	(fp)->_extra->fl_owner = NULL; \
+	(fp)->_extra->fl_count = 0; \
+}
+
Index: lib/libc/stdio/refill.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/refill.c,v
retrieving revision 1.6
diff -u -u -r1.6 refill.c
--- lib/libc/stdio/refill.c	31 Jan 2005 22:29:40 -0000	1.6
+++ lib/libc/stdio/refill.c	7 May 2005 05:44:14 -0000
@@ -99,7 +99,7 @@
 		if (HASUB(fp)) {
 			FREEUB(fp);
 			if ((fp->_r = fp->_ur) != 0) {
-				fp->_p = fp->_up;
+				fp->_p = fp->_extra->_up;
 				return (0);
 			}
 		}
Index: lib/libc/stdio/snprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/snprintf.c,v
retrieving revision 1.3
diff -u -u -r1.3 snprintf.c
--- lib/libc/stdio/snprintf.c	7 Jun 2004 20:35:41 -0000	1.3
+++ lib/libc/stdio/snprintf.c	7 May 2005 05:44:14 -0000
@@ -42,6 +42,8 @@
 #include <stdio.h>
 #include <stdarg.h>
 
+#include "local.h"
+
 int
 snprintf(char *str, size_t n, char const *fmt, ...)
 {
@@ -49,6 +51,7 @@
 	int ret;
 	va_list ap;
 	FILE f;
+	struct __sFILEX ext;
 
 	on = n;
 	if (n != 0)
@@ -60,7 +63,9 @@
 	f._flags = __SWR | __SSTR;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = n;
-	ret = vfprintf(&f, fmt, ap);
+	f._extra = &ext;
+	INITEXTRA(&f);
+	ret = __vfprintf(&f, fmt, ap);		/* Use unlocked __vfprintf */
 	if (on > 0)
 		*f._p = '\0';
 	va_end(ap);
Index: lib/libc/stdio/sprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/sprintf.c,v
retrieving revision 1.3
diff -u -u -r1.3 sprintf.c
--- lib/libc/stdio/sprintf.c	7 Jun 2004 20:35:41 -0000	1.3
+++ lib/libc/stdio/sprintf.c	7 May 2005 05:44:14 -0000
@@ -49,13 +49,16 @@
 	int ret;
 	va_list ap;
 	FILE f;
+	struct __sFILEX ext;
 
 	f._file = -1;
 	f._flags = __SWR | __SSTR;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = INT_MAX;
+	f._extra = &ext;
+	INITEXTRA(&f);
 	va_start(ap, fmt);
-	ret = vfprintf(&f, fmt, ap);
+	ret = __vfprintf(&f, fmt, ap);		/* Use unlocked __vfprintf */
 	va_end(ap);
 	*f._p = 0;
 	return (ret);
Index: lib/libc/stdio/sscanf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/sscanf.c,v
retrieving revision 1.4
diff -u -u -r1.4 sscanf.c
--- lib/libc/stdio/sscanf.c	7 Jun 2004 20:35:41 -0000	1.4
+++ lib/libc/stdio/sscanf.c	7 May 2005 05:44:14 -0000
@@ -59,6 +59,7 @@
 	int ret;
 	va_list ap;
 	FILE f;
+	struct __sFILEX ext;
 
 	f._file = -1;
 	f._flags = __SRD;
@@ -67,6 +68,8 @@
 	f._read = eofread;
 	f._ub._base = NULL;
 	f._lb._base = NULL;
+	f._extra = &ext;
+	INITEXTRA(&f);
 	va_start(ap, fmt);
 	ret = __svfscanf(&f, fmt, ap);
 	va_end(ap);
Index: lib/libc/stdio/ungetc.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/ungetc.c,v
retrieving revision 1.4
diff -u -u -r1.4 ungetc.c
--- lib/libc/stdio/ungetc.c	31 Jan 2005 22:29:40 -0000	1.4
+++ lib/libc/stdio/ungetc.c	7 May 2005 05:44:18 -0000
@@ -163,7 +163,7 @@
 	 * Initially, we will use the `reserve' buffer.
 	 */
 	fp->_ur = fp->_r;
-	fp->_up = fp->_p;
+	fp->_extra->_up = fp->_p;
 	fp->_ub._base = fp->_ubuf;
 	fp->_ub._size = sizeof(fp->_ubuf);
 	fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
Index: lib/libc/stdio/vasprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vasprintf.c,v
retrieving revision 1.4
diff -u -u -r1.4 vasprintf.c
--- lib/libc/stdio/vasprintf.c	31 Jan 2005 22:29:40 -0000	1.4
+++ lib/libc/stdio/vasprintf.c	7 May 2005 05:44:18 -0000
@@ -41,6 +41,7 @@
 {
 	int ret;
 	FILE f;
+	struct __sFILEX ext;
 
 	f._file = -1;
 	f._flags = __SWR | __SSTR | __SALC;
@@ -51,6 +52,8 @@
 		return (-1);
 	}
 	f._bf._size = f._w = 127;		/* Leave room for the NULL */
+	f._extra = &ext;
+	INITEXTRA(&f);
 	ret = __vfprintf(&f, fmt, ap);
 	*f._p = '\0';
 	f._bf._base = reallocf(f._bf._base, f._bf._size + 1);
Index: lib/libc/stdio/vfprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vfprintf.c,v
retrieving revision 1.8
diff -u -u -r1.8 vfprintf.c
--- lib/libc/stdio/vfprintf.c	21 Apr 2005 16:36:35 -0000	1.8
+++ lib/libc/stdio/vfprintf.c	7 May 2005 05:44:29 -0000
@@ -158,6 +158,7 @@
 	fake._file = fp->_file;
 	fake._cookie = fp->_cookie;
 	fake._write = fp->_write;
+	fake._extra = fp->_extra;
 
 	/* set up the buffer */
 	fake._bf._base = fake._p = buf;
Index: lib/libc/stdio/vsnprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vsnprintf.c,v
retrieving revision 1.4
diff -u -u -r1.4 vsnprintf.c
--- lib/libc/stdio/vsnprintf.c	31 Jan 2005 22:29:40 -0000	1.4
+++ lib/libc/stdio/vsnprintf.c	7 May 2005 05:44:29 -0000
@@ -50,6 +50,7 @@
 	int ret;
 	char dummy;
 	FILE f;
+	struct __sFILEX ext;
 
 	on = n;
 	if (n != 0)
@@ -65,6 +66,8 @@
 	f._flags = __SWR | __SSTR;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = n;
+	f._extra = &ext;
+	INITEXTRA(&f);
 	ret = __vfprintf(&f, fmt, ap);
 	if (on > 0)
 		*f._p = '\0';
Index: lib/libc/stdio/vsprintf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vsprintf.c,v
retrieving revision 1.4
diff -u -u -r1.4 vsprintf.c
--- lib/libc/stdio/vsprintf.c	31 Jan 2005 22:29:40 -0000	1.4
+++ lib/libc/stdio/vsprintf.c	7 May 2005 05:44:31 -0000
@@ -48,11 +48,14 @@
 {
 	int ret;
 	FILE f;
+	struct __sFILEX ext;
 
 	f._file = -1;
 	f._flags = __SWR | __SSTR;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = INT_MAX;
+	f._extra = &ext;
+	INITEXTRA(&f);
 	ret = __vfprintf(&f, fmt, ap);
 	*f._p = 0;
 	return (ret);
Index: lib/libc/stdio/vsscanf.c
===================================================================
RCS file: /cvs/src/lib/libc/stdio/vsscanf.c,v
retrieving revision 1.5
diff -u -u -r1.5 vsscanf.c
--- lib/libc/stdio/vsscanf.c	7 Jun 2004 20:35:41 -0000	1.5
+++ lib/libc/stdio/vsscanf.c	7 May 2005 05:44:31 -0000
@@ -41,6 +41,7 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
+#include "local.h"
 
 static int
 eofread (void *, char *, int);
@@ -57,6 +58,7 @@
 vsscanf(const char *str, const char *fmt, va_list ap)
 {
 	FILE f;
+	struct __sFILEX ext;
 
 	f._file = -1;
 	f._flags = __SRD;
@@ -65,5 +67,7 @@
 	f._read = eofread;
 	f._ub._base = NULL;
 	f._lb._base = NULL;
+	f._extra = &ext;
+	INITEXTRA(&f);
 	return (__svfscanf(&f, fmt, ap));
 }




More information about the Submit mailing list