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