summaryrefslogtreecommitdiff
path: root/libitm/config/posix
diff options
context:
space:
mode:
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.cc189
-rw-r--r--libitm/config/posix/rwlock.h73
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