summaryrefslogtreecommitdiff
path: root/lib/libc/stdio/findfp.c
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2009-10-21 16:04:24 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2009-10-21 16:04:24 +0000
commit41f63f502ca80eb7786b814aad26bbb067f253ce (patch)
treed43150b93956d00bef9acc8b52e692aa590aca5b /lib/libc/stdio/findfp.c
parent99b8328b2511887d52f6373c2338c996ffac1768 (diff)
Fix the handle locking in stdio to use flockfile/funlockfile
internally when and where required. Macros in <stdio.h> are updated to automatically call the underlying functions when the process is threaded to obtain the necessary locking. A private mutex is added to protect __sglue, the internal list of FILE handles, and another to protect the one-time initialization. Some routines in libc that use getc() change to use getc_unlocked() as they're either protected by their own lock or aren't thread-safe routines anyway. ok kurt@, earlier version tested by sthen@ and jj@
Diffstat (limited to 'lib/libc/stdio/findfp.c')
-rw-r--r--lib/libc/stdio/findfp.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c
index 27d19843208..f3e000c3591 100644
--- a/lib/libc/stdio/findfp.c
+++ b/lib/libc/stdio/findfp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: findfp.c,v 1.9 2005/08/08 08:05:36 espie Exp $ */
+/* $OpenBSD: findfp.c,v 1.10 2009/10/21 16:04:23 guenther Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
@@ -39,6 +39,7 @@
#include <string.h>
#include "local.h"
#include "glue.h"
+#include "thread_private.h"
int __sdidinit;
@@ -54,6 +55,8 @@ int __sdidinit;
static FILE usual[FOPEN_MAX - 3];
static struct __sfileext usualext[FOPEN_MAX - 3];
static struct glue uglue = { 0, FOPEN_MAX - 3, usual };
+static struct glue *lastglue = &uglue;
+_THREAD_PRIVATE_MUTEX(__sfp_mutex);
struct __sfileext __sFext[3];
FILE __sF[3] = {
@@ -104,16 +107,25 @@ __sfp(void)
if (!__sdidinit)
__sinit();
- for (g = &__sglue;; g = g->next) {
+
+ _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
+ for (g = &__sglue; g != NULL; g = g->next) {
for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
if (fp->_flags == 0)
goto found;
- if (g->next == NULL && (g->next = moreglue(NDYNAMIC)) == NULL)
- break;
}
- return (NULL);
+
+ /* release lock while mallocing */
+ _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
+ if ((g = moreglue(NDYNAMIC)) == NULL)
+ return (NULL);
+ _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
+ lastglue->next = g;
+ lastglue = g;
+ fp = g->iobs;
found:
fp->_flags = 1; /* reserve this slot; caller sets real flags */
+ _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
fp->_p = NULL; /* no current pointer */
fp->_w = 0; /* nothing to read or write */
fp->_r = 0;
@@ -143,8 +155,12 @@ f_prealloc(void)
n = getdtablesize() - FOPEN_MAX + 20; /* 20 for slop. */
for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
/* void */;
- if (n > 0)
- g->next = moreglue(n);
+ if (n > 0 && ((g = moreglue(n)) != NULL)) {
+ _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
+ lastglue->next = g;
+ lastglue = g;
+ _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
+ }
}
/*
@@ -168,12 +184,18 @@ _cleanup(void)
void
__sinit(void)
{
+ _THREAD_PRIVATE_MUTEX(__sinit_mutex);
int i;
+ _THREAD_PRIVATE_MUTEX_LOCK(__sinit_mutex);
+ if (__sdidinit)
+ goto out; /* bail out if caller lost the race */
for (i = 0; i < FOPEN_MAX - 3; i++) {
_FILEEXT_SETUP(usual+i, usualext+i);
}
/* make sure we clean up on exit */
__atexit_register_cleanup(_cleanup); /* conservative */
__sdidinit = 1;
+out:
+ _THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex);
}