diff options
author | Kurt Miller <kurt@cvs.openbsd.org> | 2009-11-09 00:18:29 +0000 |
---|---|---|
committer | Kurt Miller <kurt@cvs.openbsd.org> | 2009-11-09 00:18:29 +0000 |
commit | ad0592d657a970d3b3d8200773732a354fad0461 (patch) | |
tree | 2d36a0624d8d3c7fac96e04ac86511d85bbcc56f /lib/libpthread/uthread | |
parent | 13102e76b8d893f7a1f4a778cc16d5e67e719a12 (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.
committing on behalf of and okay guenther@ now that we have install
media space available.
Diffstat (limited to 'lib/libpthread/uthread')
-rw-r--r-- | lib/libpthread/uthread/uthread_file.c | 253 |
1 files changed, 122 insertions, 131 deletions
diff --git a/lib/libpthread/uthread/uthread_file.c b/lib/libpthread/uthread/uthread_file.c index d8c9cdcb818..25c2d0945cc 100644 --- a/lib/libpthread/uthread/uthread_file.c +++ b/lib/libpthread/uthread/uthread_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_file.c,v 1.16 2009/10/22 01:23:16 guenther Exp $ */ +/* $OpenBSD: uthread_file.c,v 1.17 2009/11/09 00:18:27 kurt Exp $ */ /* * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. * All rights reserved. @@ -41,6 +41,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <sys/queue.h> #ifdef _THREAD_SAFE #include <pthread.h> @@ -173,68 +174,65 @@ do_lock(int idx, FILE *fp) return(p); } + void flockfile(FILE * fp) { int idx = file_idx(fp); struct file_lock *p; - /* Check if this is a real file: */ - if (fileno(fp) >= 0) { - /* Lock the hash table: */ - _SPINLOCK(&hash_lock); + /* Lock the hash table: */ + _SPINLOCK(&hash_lock); - /* Check if the static array has not been initialised: */ - if (!init_done) { - /* Initialise the global array: */ - memset(flh,0,sizeof(flh)); + /* Check if the static array has not been initialised: */ + if (!init_done) { + /* Initialise the global array: */ + memset(flh,0,sizeof(flh)); - /* Flag the initialisation as complete: */ - init_done = 1; - } + /* Flag the initialisation as complete: */ + init_done = 1; + } - /* Get a pointer to any existing lock for the file: */ - if ((p = find_lock(idx, fp)) == NULL) { - /* - * The file is not locked, so this thread can - * grab the lock: - */ - p = do_lock(idx, fp); + /* Get a pointer to any existing lock for the file: */ + if ((p = find_lock(idx, fp)) == NULL) { + /* + * The file is not locked, so this thread can + * grab the lock: + */ + p = do_lock(idx, fp); - /* Unlock the hash table: */ - _SPINUNLOCK(&hash_lock); + /* Unlock the hash table: */ + _SPINUNLOCK(&hash_lock); + /* + * The file is already locked, so check if the + * running thread is the owner: + */ + } else if (p->owner == _thread_run) { /* - * The file is already locked, so check if the - * running thread is the owner: + * The running thread is already the + * owner, so increment the count of + * the number of times it has locked + * the file: */ - } else if (p->owner == _thread_run) { - /* - * The running thread is already the - * owner, so increment the count of - * the number of times it has locked - * the file: - */ - p->count++; + p->count++; - /* Unlock the hash table: */ - _SPINUNLOCK(&hash_lock); - } else { - /* - * The file is locked for another thread. - * Append this thread to the queue of - * threads waiting on the lock. - */ - TAILQ_INSERT_TAIL(&p->l_head,_thread_run,qe); + /* Unlock the hash table: */ + _SPINUNLOCK(&hash_lock); + } else { + /* + * The file is locked for another thread. + * Append this thread to the queue of + * threads waiting on the lock. + */ + TAILQ_INSERT_TAIL(&p->l_head,_thread_run,qe); - /* Unlock the hash table: */ - _SPINUNLOCK(&hash_lock); + /* Unlock the hash table: */ + _SPINUNLOCK(&hash_lock); - /* Wait on the FILE lock: */ - _thread_kern_sched_state(PS_FILE_WAIT, "", 0); - } + /* Wait on the FILE lock: */ + _thread_kern_sched_state(PS_FILE_WAIT, "", 0); } - return; } int @@ -244,48 +242,45 @@ ftrylockfile(FILE * fp) int idx = file_idx(fp); struct file_lock *p; - /* Check if this is a real file: */ - if (fileno(fp) >= 0) { - /* Lock the hash table: */ - _SPINLOCK(&hash_lock); + /* Lock the hash table: */ + _SPINLOCK(&hash_lock); - /* Get a pointer to any existing lock for the file: */ - if ((p = find_lock(idx, fp)) == NULL) { - /* - * The file is not locked, so this thread can - * grab the lock: - */ - p = do_lock(idx, fp); + /* Get a pointer to any existing lock for the file: */ + if ((p = find_lock(idx, fp)) == NULL) { + /* + * The file is not locked, so this thread can + * grab the lock: + */ + p = do_lock(idx, fp); + /* + * The file is already locked, so check if the + * running thread is the owner: + */ + } else if (p->owner == _thread_run) { /* - * The file is already locked, so check if the - * running thread is the owner: + * The running thread is already the + * owner, so increment the count of + * the number of times it has locked + * the file: */ - } else if (p->owner == _thread_run) { - /* - * The running thread is already the - * owner, so increment the count of - * the number of times it has locked - * the file: - */ - p->count++; - } else { - /* - * The file is locked for another thread, - * so this try fails. - */ - p = NULL; - } + p->count++; + } else { + /* + * The file is locked for another thread, + * so this try fails. + */ + p = NULL; + } - /* Check if the lock was obtained: */ - if (p != NULL) - /* Return success: */ - ret = 0; + /* Check if the lock was obtained: */ + if (p != NULL) + /* Return success: */ + ret = 0; - /* Unlock the hash table: */ - _SPINUNLOCK(&hash_lock); + /* Unlock the hash table: */ + _SPINUNLOCK(&hash_lock); - } return (ret); } @@ -295,68 +290,64 @@ funlockfile(FILE * fp) int idx = file_idx(fp); struct file_lock *p; - /* Check if this is a real file: */ - if (fileno(fp) >= 0) { - /* - * Defer signals to protect the scheduling queues from - * access by the signal handler: - */ - _thread_kern_sig_defer(); + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); - /* Lock the hash table: */ - _SPINLOCK(&hash_lock); + /* Lock the hash table: */ + _SPINLOCK(&hash_lock); + /* + * Get a pointer to the lock for the file and check that + * the running thread is the one with the lock: + */ + if ((p = find_lock(idx, fp)) != NULL && + p->owner == _thread_run) { /* - * Get a pointer to the lock for the file and check that - * the running thread is the one with the lock: + * Check if this thread has locked the FILE + * more than once: */ - if ((p = find_lock(idx, fp)) != NULL && - p->owner == _thread_run) { + if (p->count > 1) /* - * Check if this thread has locked the FILE - * more than once: + * Decrement the count of the number of + * times the running thread has locked this + * file: */ - if (p->count > 1) - /* - * Decrement the count of the number of - * times the running thread has locked this - * file: - */ - p->count--; - else { + p->count--; + else { + /* + * The running thread will release the + * lock now: + */ + p->count = 0; + + /* Get the new owner of the lock: */ + if ((p->owner = TAILQ_FIRST(&p->l_head)) != NULL) { + /* Pop the thread off the queue: */ + TAILQ_REMOVE(&p->l_head,p->owner,qe); + /* - * The running thread will release the - * lock now: + * This is the first lock for the new + * owner: */ - p->count = 0; - - /* Get the new owner of the lock: */ - if ((p->owner = TAILQ_FIRST(&p->l_head)) != NULL) { - /* Pop the thread off the queue: */ - TAILQ_REMOVE(&p->l_head,p->owner,qe); - - /* - * This is the first lock for the new - * owner: - */ - p->count = 1; - - /* Allow the new owner to run: */ - PTHREAD_NEW_STATE(p->owner,PS_RUNNING); - } + p->count = 1; + + /* Allow the new owner to run: */ + PTHREAD_NEW_STATE(p->owner,PS_RUNNING); } } + } - /* Unlock the hash table: */ - _SPINUNLOCK(&hash_lock); + /* Unlock the hash table: */ + _SPINUNLOCK(&hash_lock); - /* - * Undefer and handle pending signals, yielding if - * necessary: - */ - _thread_kern_sig_undefer(); - } - return; + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); } #endif |