mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			185 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* Copyright (C) 2009-2014 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"
 | |
| 
 | |
| using namespace GTM;
 | |
| 
 | |
| struct clone_entry
 | |
| {
 | |
|   void *orig, *clone;
 | |
| };
 | |
| 
 | |
| struct clone_table
 | |
| {
 | |
|   clone_entry *table;
 | |
|   size_t size;
 | |
|   clone_table *next;
 | |
| };
 | |
| 
 | |
| static clone_table *all_tables;
 | |
| 
 | |
| static void *
 | |
| find_clone (void *ptr)
 | |
| {
 | |
|   clone_table *table;
 | |
| 
 | |
|   for (table = all_tables; table ; table = table->next)
 | |
|     {
 | |
|       clone_entry *t = table->table;
 | |
|       size_t lo = 0, hi = table->size, i;
 | |
| 
 | |
|       /* Quick test for whether PTR is present in this table.  */
 | |
|       if (ptr < t[0].orig || ptr > t[hi - 1].orig)
 | |
| 	continue;
 | |
| 
 | |
|       /* Otherwise binary search.  */
 | |
|       while (lo < hi)
 | |
| 	{
 | |
| 	  i = (lo + hi) / 2;
 | |
| 	  if (ptr < t[i].orig)
 | |
| 	    hi = i;
 | |
| 	  else if (ptr > t[i].orig)
 | |
| 	    lo = i + 1;
 | |
| 	  else
 | |
| 	    return t[i].clone;
 | |
| 	}
 | |
| 
 | |
|       /* Given the quick test above, if we don't find the entry in
 | |
| 	 this table then it doesn't exist.  */
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| void * ITM_REGPARM
 | |
| _ITM_getTMCloneOrIrrevocable (void *ptr)
 | |
| {
 | |
|   void *ret = find_clone (ptr);
 | |
|   if (ret)
 | |
|     return ret;
 | |
| 
 | |
|   gtm_thr()->serialirr_mode ();
 | |
| 
 | |
|   return ptr;
 | |
| }
 | |
| 
 | |
| void * ITM_REGPARM
 | |
| _ITM_getTMCloneSafe (void *ptr)
 | |
| {
 | |
|   void *ret = find_clone (ptr);
 | |
|   if (ret == NULL)
 | |
|     abort ();
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| static int
 | |
| clone_entry_compare (const void *a, const void *b)
 | |
| {
 | |
|   const clone_entry *aa = (const clone_entry *)a;
 | |
|   const clone_entry *bb = (const clone_entry *)b;
 | |
| 
 | |
|   if (aa->orig < bb->orig)
 | |
|     return -1;
 | |
|   else if (aa->orig > bb->orig)
 | |
|     return 1;
 | |
|   else
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // Within find_clone, we know that we are inside a transaction.  Because
 | |
| // of that, we have already synchronized with serial_lock.  By taking the
 | |
| // serial_lock for write, we exclude all transactions while we make this
 | |
| // change to the clone tables, without having to synchronize on a separate
 | |
| // lock.  Do be careful not to attempt a recursive write lock.
 | |
| 
 | |
| class ExcludeTransaction
 | |
| {
 | |
|   bool do_lock;
 | |
| 
 | |
|  public:
 | |
|   ExcludeTransaction()
 | |
|   {
 | |
|     gtm_thread *tx = gtm_thr();
 | |
|     do_lock = !(tx && (tx->state & gtm_thread::STATE_SERIAL));
 | |
| 
 | |
|     if (do_lock)
 | |
|       gtm_thread::serial_lock.write_lock ();
 | |
|   }
 | |
| 
 | |
|   ~ExcludeTransaction()
 | |
|   {
 | |
|     if (do_lock)
 | |
|       gtm_thread::serial_lock.write_unlock ();
 | |
|   }
 | |
| };
 | |
| 
 | |
| } // end anon namespace
 | |
| 
 | |
| 
 | |
| void
 | |
| _ITM_registerTMCloneTable (void *xent, size_t size)
 | |
| {
 | |
|   clone_entry *ent = static_cast<clone_entry *>(xent);
 | |
|   clone_table *table;
 | |
| 
 | |
|   table = (clone_table *) xmalloc (sizeof (clone_table));
 | |
|   table->table = ent;
 | |
|   table->size = size;
 | |
| 
 | |
|   qsort (ent, size, sizeof (clone_entry), clone_entry_compare);
 | |
| 
 | |
|   // Hold the serial_lock while we update the ALL_TABLES datastructure.
 | |
|   {
 | |
|     ExcludeTransaction exclude;
 | |
|     table->next = all_tables;
 | |
|     all_tables = table;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| _ITM_deregisterTMCloneTable (void *xent)
 | |
| {
 | |
|   clone_entry *ent = static_cast<clone_entry *>(xent);
 | |
|   clone_table *tab;
 | |
| 
 | |
|   // Hold the serial_lock while we update the ALL_TABLES datastructure.
 | |
|   {
 | |
|     ExcludeTransaction exclude;
 | |
|     clone_table **pprev;
 | |
| 
 | |
|     for (pprev = &all_tables;
 | |
| 	 tab = *pprev, tab->table != ent;
 | |
| 	 pprev = &tab->next)
 | |
|       continue;
 | |
|     *pprev = tab->next;
 | |
|   }
 | |
| 
 | |
|   free (tab);
 | |
| }
 |