| /* Copyright (C) 2009-2017 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); |
| } |