diff options
Diffstat (limited to 'libitm/config/posix')
-rw-r--r-- | libitm/config/posix/cachepage.cc (renamed from libitm/config/posix/page.c) | 35 | ||||
-rw-r--r-- | libitm/config/posix/rwlock.cc | 189 | ||||
-rw-r--r-- | libitm/config/posix/rwlock.h | 73 |
3 files changed, 288 insertions, 9 deletions
diff --git a/libitm/config/posix/page.c b/libitm/config/posix/cachepage.cc index 43b840366c0..9888ef5028c 100644 --- a/libitm/config/posix/page.c +++ b/libitm/config/posix/cachepage.cc @@ -24,6 +24,10 @@ #include "libitm_i.h" +// +// We have three possibilities for alloction: mmap, memalign, posix_memalign +// + #if defined(HAVE_MMAP_ANON) || defined(HAVE_MMAP_DEV_ZERO) #include <sys/mman.h> #include <fcntl.h> @@ -32,8 +36,7 @@ #include <malloc.h> #endif - -static gtm_cacheline_page *free_pages; +namespace GTM HIDDEN { #if defined(HAVE_MMAP_ANON) # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) @@ -50,7 +53,8 @@ static int dev_zero = -1; #if defined(HAVE_MMAP_ANON) || defined(HAVE_MMAP_DEV_ZERO) /* If we get here, we've already opened /dev/zero and verified that PAGE_SIZE is valid for the system. */ -static gtm_cacheline_page * UNUSED +static gtm_cacheline_page * alloc_mmap (void) UNUSED; +static gtm_cacheline_page * alloc_mmap (void) { gtm_cacheline_page *r; @@ -131,12 +135,15 @@ init_alloc_page (void) # error "No aligned memory allocation method" #endif +static gtm_cacheline_page *free_pages; -gtm_cacheline_page * -GTM_page_alloc (void) +void * +gtm_cacheline_page::operator new (size_t size) { - gtm_cacheline_page *r = free_pages; + assert (size == sizeof (gtm_cacheline_page)); + assert (size <= PAGE_SIZE); + gtm_cacheline_page *r = free_pages; restart: if (r) { @@ -155,12 +162,20 @@ GTM_page_alloc (void) } void -GTM_page_release (gtm_cacheline_page *head, gtm_cacheline_page *tail) +gtm_cacheline_page::operator delete (void *xhead) { - gtm_cacheline_page *n, *p = free_pages; + gtm_cacheline_page *head = static_cast<gtm_cacheline_page *>(xhead); + gtm_cacheline_page *tail, *n, *p; + + if (head == 0) + return; - /* ??? We should eventually free some of these. */ + /* ??? We should eventually really free some of these. */ + for (tail = head; tail->prev != 0; tail = tail->prev) + continue; + + p = free_pages; restart: tail->prev = p; n = __sync_val_compare_and_swap (&free_pages, p, head); @@ -170,3 +185,5 @@ GTM_page_release (gtm_cacheline_page *head, gtm_cacheline_page *tail) goto restart; } } + +} // namespace GTM diff --git a/libitm/config/posix/rwlock.cc b/libitm/config/posix/rwlock.cc new file mode 100644 index 00000000000..069eec257f7 --- /dev/null +++ b/libitm/config/posix/rwlock.cc @@ -0,0 +1,189 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm 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 3 of the License, or + (at your option) any later version. + + Libitm 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +// Initialize a new RW lock. +// ??? Move this back to the header file when constexpr is implemented. + +gtm_rwlock::gtm_rwlock() + : mutex (PTHREAD_MUTEX_INITIALIZER), + c_readers (PTHREAD_COND_INITIALIZER), + c_writers (PTHREAD_COND_INITIALIZER), + c_upgrade (PTHREAD_COND_INITIALIZER), + summary (0), + a_readers (0), + w_readers (0), + w_writers (0) +{ } + +gtm_rwlock::~gtm_rwlock() +{ + pthread_mutex_destroy (&this->mutex); + pthread_cond_destroy (&this->c_readers); + pthread_cond_destroy (&this->c_writers); + pthread_cond_destroy (&this->c_upgrade); +} + +// Acquire a RW lock for reading. + +void +gtm_rwlock::read_lock () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + + // If there is a waiting upgrade, or an active writer, we must wait. + while (sum & (w_upgrade | a_writer | w_writer)) + { + this->summary = sum | w_reader; + this->w_readers++; + pthread_cond_wait (&this->c_readers, &this->mutex); + sum = this->summary; + if (--this->w_readers == 0) + sum &= ~w_reader; + } + + // Otherwise we can acquire the lock for read. + this->summary = sum | a_reader; + this->a_readers++; + + pthread_mutex_unlock(&this->mutex); +} + + +// Acquire a RW lock for writing. + +void +gtm_rwlock::write_lock () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + + // If there is a waiting upgrade, or an active reader or writer, wait. + while (sum & (w_upgrade | a_writer | a_reader)) + { + this->summary = sum | w_writer; + this->w_writers++; + pthread_cond_wait (&this->c_writers, &this->mutex); + sum = this->summary; + if (--this->w_writers == 0) + sum &= ~w_writer; + } + + // Otherwise we can acquire the lock for write. + this->summary = sum | a_writer; + + pthread_mutex_unlock(&this->mutex); +} + + +// Upgrade a RW lock that has been locked for reading to a writing lock. +// Do this without possibility of another writer incoming. Return false +// if this attempt fails (i.e. another thread also upgraded). + +bool +gtm_rwlock::write_upgrade () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + + // If there's already someone trying to upgrade, then we fail. + if (unlikely (sum & w_upgrade)) + { + pthread_mutex_unlock (&this->mutex); + return false; + } + + // If there are more active readers, then we have to wait. + if (--this->a_readers > 0) + { + this->summary = sum | w_upgrade; + pthread_cond_wait (&this->c_upgrade, &this->mutex); + sum = this->summary & ~w_upgrade; + // We only return from upgrade when we've got it; don't loop. + assert ((sum & (a_reader | a_writer)) == 0); + } + + // Otherwise we can upgrade to writer. + this->summary = sum | a_writer; + + pthread_mutex_unlock (&this->mutex); + return true; +} + + +// Release a RW lock from reading. + +void +gtm_rwlock::read_unlock () +{ + pthread_mutex_lock (&this->mutex); + + // If there are no more active readers, we may need to wake someone. + if (--this->a_readers == 0) + { + unsigned int sum = this->summary; + this->summary = sum & ~a_reader; + + // If there is a waiting upgrade, wake it. + if (unlikely (sum & w_upgrade)) + pthread_cond_signal (&this->c_upgrade); + + // If there is a waiting writer, wake it. + else if (unlikely (sum & w_writer)) + pthread_cond_signal (&this->c_writers); + } + + pthread_mutex_unlock (&this->mutex); +} + + +// Release a RW lock from writing. + +void +gtm_rwlock::write_unlock () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + this->summary = sum & ~a_writer; + + // If there is a waiting writer, wake it. + if (unlikely (sum & w_writer)) + pthread_cond_signal (&this->c_writers); + + // If there are waiting readers, wake them. + else if (unlikely (sum & w_reader)) + pthread_cond_broadcast (&this->c_readers); + + pthread_mutex_unlock (&this->mutex); +} + +} // namespace GTM diff --git a/libitm/config/posix/rwlock.h b/libitm/config/posix/rwlock.h new file mode 100644 index 00000000000..85544455da8 --- /dev/null +++ b/libitm/config/posix/rwlock.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm 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 3 of the License, or + (at your option) any later version. + + Libitm 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef GTM_RWLOCK_H +#define GTM_RWLOCK_H + +#include <pthread.h> + +namespace GTM HIDDEN { + +// This datastructure is similar to the POSIX pthread_rwlock_t except +// that we also provide for upgrading a reader->writer lock, with a +// positive indication of failure (another writer acquired the lock +// before we were able to acquire). +// +// In this implementation, rw upgrade is given highest priority access, +// and writers are given priority over readers. + +class gtm_rwlock +{ + pthread_mutex_t mutex; // Held if manipulating any field. + pthread_cond_t c_readers; // Readers wait here + pthread_cond_t c_writers; // Writers wait here + pthread_cond_t c_upgrade; // An upgrader waits here + + static const unsigned w_upgrade = 1; // A reader waiting for upgrade + static const unsigned a_writer = 2; // An active writer. + static const unsigned w_writer = 4; // The w_writers field != 0 + static const unsigned a_reader = 8; // The a_readers field != 0 + static const unsigned w_reader = 16; // The w_readers field != 0 + + unsigned int summary; // Bitmask of the above. + unsigned int a_readers; // Nr active readers + unsigned int w_readers; // Nr waiting readers + unsigned int w_writers; // Nr waiting writers + + public: + gtm_rwlock(); + ~gtm_rwlock(); + + void read_lock (); + void read_unlock (); + + void write_lock (); + void write_unlock (); + + bool write_upgrade (); +}; + +} // namespace GTM + +#endif // GTM_RWLOCK_H |