📄 lock.c
字号:
/* Locking in multithreaded situations. Copyright (C) 2005-2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *//* Written by Bruno Haible <bruno@clisp.org>, 2005. Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h, gthr-win32.h. */#include <config.h>#include "lock.h"/* ========================================================================= */#if USE_POSIX_THREADS/* Use the POSIX threads library. */# if PTHREAD_IN_USE_DETECTION_HARD/* The function to be executed by a dummy thread. */static void *dummy_thread_func (void *arg){ return arg;}intglthread_in_use (void){ static int tested; static int result; /* 1: linked with -lpthread, 0: only with libc */ if (!tested) { pthread_t thread; if (pthread_create (&thread, NULL, dummy_thread_func, NULL) != 0) /* Thread creation failed. */ result = 0; else { /* Thread creation works. */ void *retval; if (pthread_join (thread, &retval) != 0) abort (); result = 1; } tested = 1; } return result;}# endif/* -------------------------- gl_lock_t datatype -------------------------- *//* ------------------------- gl_rwlock_t datatype ------------------------- */# if HAVE_PTHREAD_RWLOCK# if !defined PTHREAD_RWLOCK_INITIALIZERvoidglthread_rwlock_init (gl_rwlock_t *lock){ if (pthread_rwlock_init (&lock->rwlock, NULL) != 0) abort (); lock->initialized = 1;}voidglthread_rwlock_rdlock (gl_rwlock_t *lock){ if (!lock->initialized) { if (pthread_mutex_lock (&lock->guard) != 0) abort (); if (!lock->initialized) glthread_rwlock_init (lock); if (pthread_mutex_unlock (&lock->guard) != 0) abort (); } if (pthread_rwlock_rdlock (&lock->rwlock) != 0) abort ();}voidglthread_rwlock_wrlock (gl_rwlock_t *lock){ if (!lock->initialized) { if (pthread_mutex_lock (&lock->guard) != 0) abort (); if (!lock->initialized) glthread_rwlock_init (lock); if (pthread_mutex_unlock (&lock->guard) != 0) abort (); } if (pthread_rwlock_wrlock (&lock->rwlock) != 0) abort ();}voidglthread_rwlock_unlock (gl_rwlock_t *lock){ if (!lock->initialized) abort (); if (pthread_rwlock_unlock (&lock->rwlock) != 0) abort ();}voidglthread_rwlock_destroy (gl_rwlock_t *lock){ if (!lock->initialized) abort (); if (pthread_rwlock_destroy (&lock->rwlock) != 0) abort (); lock->initialized = 0;}# endif# elsevoidglthread_rwlock_init (gl_rwlock_t *lock){ if (pthread_mutex_init (&lock->lock, NULL) != 0) abort (); if (pthread_cond_init (&lock->waiting_readers, NULL) != 0) abort (); if (pthread_cond_init (&lock->waiting_writers, NULL) != 0) abort (); lock->waiting_writers_count = 0; lock->runcount = 0;}voidglthread_rwlock_rdlock (gl_rwlock_t *lock){ if (pthread_mutex_lock (&lock->lock) != 0) abort (); /* Test whether only readers are currently running, and whether the runcount field will not overflow. */ /* POSIX says: "It is implementation-defined whether the calling thread acquires the lock when a writer does not hold the lock and there are writers blocked on the lock." Let's say, no: give the writers a higher priority. */ while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0)) { /* This thread has to wait for a while. Enqueue it among the waiting_readers. */ if (pthread_cond_wait (&lock->waiting_readers, &lock->lock) != 0) abort (); } lock->runcount++; if (pthread_mutex_unlock (&lock->lock) != 0) abort ();}voidglthread_rwlock_wrlock (gl_rwlock_t *lock){ if (pthread_mutex_lock (&lock->lock) != 0) abort (); /* Test whether no readers or writers are currently running. */ while (!(lock->runcount == 0)) { /* This thread has to wait for a while. Enqueue it among the waiting_writers. */ lock->waiting_writers_count++; if (pthread_cond_wait (&lock->waiting_writers, &lock->lock) != 0) abort (); lock->waiting_writers_count--; } lock->runcount--; /* runcount becomes -1 */ if (pthread_mutex_unlock (&lock->lock) != 0) abort ();}voidglthread_rwlock_unlock (gl_rwlock_t *lock){ if (pthread_mutex_lock (&lock->lock) != 0) abort (); if (lock->runcount < 0) { /* Drop a writer lock. */ if (!(lock->runcount == -1)) abort (); lock->runcount = 0; } else { /* Drop a reader lock. */ if (!(lock->runcount > 0)) abort (); lock->runcount--; } if (lock->runcount == 0) { /* POSIX recommends that "write locks shall take precedence over read locks", to avoid "writer starvation". */ if (lock->waiting_writers_count > 0) { /* Wake up one of the waiting writers. */ if (pthread_cond_signal (&lock->waiting_writers) != 0) abort (); } else { /* Wake up all waiting readers. */ if (pthread_cond_broadcast (&lock->waiting_readers) != 0) abort (); } } if (pthread_mutex_unlock (&lock->lock) != 0) abort ();}voidglthread_rwlock_destroy (gl_rwlock_t *lock){ if (pthread_mutex_destroy (&lock->lock) != 0) abort (); if (pthread_cond_destroy (&lock->waiting_readers) != 0) abort (); if (pthread_cond_destroy (&lock->waiting_writers) != 0) abort ();}# endif/* --------------------- gl_recursive_lock_t datatype --------------------- */# if HAVE_PTHREAD_MUTEX_RECURSIVE# if !(defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)voidglthread_recursive_lock_init (gl_recursive_lock_t *lock){ pthread_mutexattr_t attributes; if (pthread_mutexattr_init (&attributes) != 0) abort (); if (pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) abort (); if (pthread_mutex_init (&lock->recmutex, &attributes) != 0) abort (); if (pthread_mutexattr_destroy (&attributes) != 0) abort (); lock->initialized = 1;}voidglthread_recursive_lock_lock (gl_recursive_lock_t *lock){ if (!lock->initialized) { if (pthread_mutex_lock (&lock->guard) != 0) abort (); if (!lock->initialized) glthread_recursive_lock_init (lock); if (pthread_mutex_unlock (&lock->guard) != 0) abort (); } if (pthread_mutex_lock (&lock->recmutex) != 0) abort ();}voidglthread_recursive_lock_unlock (gl_recursive_lock_t *lock){ if (!lock->initialized) abort (); if (pthread_mutex_unlock (&lock->recmutex) != 0) abort ();}voidglthread_recursive_lock_destroy (gl_recursive_lock_t *lock){ if (!lock->initialized) abort (); if (pthread_mutex_destroy (&lock->recmutex) != 0) abort (); lock->initialized = 0;}# endif# elsevoidglthread_recursive_lock_init (gl_recursive_lock_t *lock){ if (pthread_mutex_init (&lock->mutex, NULL) != 0) abort (); lock->owner = (pthread_t) 0; lock->depth = 0;}voidglthread_recursive_lock_lock (gl_recursive_lock_t *lock){ pthread_t self = pthread_self (); if (lock->owner != self) { if (pthread_mutex_lock (&lock->mutex) != 0) abort (); lock->owner = self; } if (++(lock->depth) == 0) /* wraparound? */ abort ();}voidglthread_recursive_lock_unlock (gl_recursive_lock_t *lock){ if (lock->owner != pthread_self ()) abort (); if (lock->depth == 0) abort (); if (--(lock->depth) == 0) { lock->owner = (pthread_t) 0; if (pthread_mutex_unlock (&lock->mutex) != 0) abort (); }}voidglthread_recursive_lock_destroy (gl_recursive_lock_t *lock){ if (lock->owner != (pthread_t) 0) abort (); if (pthread_mutex_destroy (&lock->mutex) != 0) abort ();}# endif/* -------------------------- gl_once_t datatype -------------------------- */static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;intglthread_once_singlethreaded (pthread_once_t *once_control){ /* We don't know whether pthread_once_t is an integer type, a floating-point type, a pointer type, or a structure type. */ char *firstbyte = (char *)once_control; if (*firstbyte == *(const char *)&fresh_once) { /* First time use of once_control. Invert the first byte. */ *firstbyte = ~ *(const char *)&fresh_once; return 1; } else return 0;}#endif/* ========================================================================= */#if USE_PTH_THREADS/* Use the GNU Pth threads library. *//* -------------------------- gl_lock_t datatype -------------------------- *//* ------------------------- gl_rwlock_t datatype ------------------------- *//* --------------------- gl_recursive_lock_t datatype --------------------- *//* -------------------------- gl_once_t datatype -------------------------- */voidglthread_once_call (void *arg){ void (**gl_once_temp_addr) (void) = (void (**) (void)) arg; void (*initfunction) (void) = *gl_once_temp_addr; initfunction ();}intglthread_once_singlethreaded (pth_once_t *once_control){ /* We know that pth_once_t is an integer type. */ if (*once_control == PTH_ONCE_INIT) { /* First time use of once_control. Invert the marker. */ *once_control = ~ PTH_ONCE_INIT; return 1; } else return 0;}#endif/* ========================================================================= */#if USE_SOLARIS_THREADS/* Use the old Solaris threads library. *//* -------------------------- gl_lock_t datatype -------------------------- *//* ------------------------- gl_rwlock_t datatype ------------------------- *//* --------------------- gl_recursive_lock_t datatype --------------------- */voidglthread_recursive_lock_init (gl_recursive_lock_t *lock){ if (mutex_init (&lock->mutex, USYNC_THREAD, NULL) != 0) abort (); lock->owner = (thread_t) 0; lock->depth = 0;}voidglthread_recursive_lock_lock (gl_recursive_lock_t *lock){ thread_t self = thr_self (); if (lock->owner != self) { if (mutex_lock (&lock->mutex) != 0) abort (); lock->owner = self; } if (++(lock->depth) == 0) /* wraparound? */ abort ();}voidglthread_recursive_lock_unlock (gl_recursive_lock_t *lock){ if (lock->owner != thr_self ()) abort (); if (lock->depth == 0) abort (); if (--(lock->depth) == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -