185 lines
4.1 KiB
C++
185 lines
4.1 KiB
C++
|
/* Copyright (C) 2009-2022 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);
|
||
|
}
|