===================================================================
@@ -90,6 +90,7 @@ class wbetl_dispatch : public gtm_dispat
virtual void rollback();
virtual void reinit();
virtual void fini();
+ virtual bool trydropreference (void *, size_t);
};
/* Check if W is one of our write locks. */
@@ -131,6 +132,8 @@ wbetl_dispatch::validate ()
{
w_entry *w = (w_entry *) gtm_stmlock_get_addr (l);
+ // If someone has locked us, it better be by someone in the
+ // current thread.
if (!local_w_entry_p (w))
return false;
}
@@ -521,6 +524,83 @@ wbetl_dispatch::fini ()
delete this;
}
+/* Attempt to drop any internal references to PTR. Return TRUE if successful.
+
+ This is an adaptation of the transactional memcpy function.
+
+ What we do here is flush out the current transactional content of
+ PTR to real memory, and remove the write mask bits associated with
+ it so future commits will ignore this piece of memory. */
+
+bool
+wbetl_dispatch::trydropreference (void *ptr, size_t size)
+{
+ if (size == 0)
+ return true;
+
+ if (!validate ())
+ return false;
+
+ uintptr_t isrc = (uintptr_t)ptr;
+ // The position in the source cacheline where *PTR starts.
+ uintptr_t sofs = isrc & (CACHELINE_SIZE - 1);
+ gtm_cacheline *src
+ = reinterpret_cast<gtm_cacheline *>(isrc & -CACHELINE_SIZE);
+ unsigned char *dst = (unsigned char *)ptr;
+ gtm_dispatch::mask_pair pair;
+
+ // If we're trying to drop a reference, we should already have a
+ // write lock on it. If we don't have one, there's no work to do.
+ if (!gtm_stmlock_owned_p (*gtm_get_stmlock (src)))
+ return true;
+
+ // We copy the data in three stages:
+
+ // (a) Copy stray bytes at the beginning that are smaller than a
+ // cacheline.
+ if (sofs != 0)
+ {
+ size_t sleft = CACHELINE_SIZE - sofs;
+ size_t min = (size <= sleft ? size : sleft);
+
+ // WaW will give us the current locked entry.
+ pair = this->write_lock (src, WaW);
+
+ // *jedi mind wave*...these aren't the droids you're looking for.
+ *pair.mask &= ~((((gtm_cacheline_mask)1 << min) - 1) << sofs);
+
+ memcpy (dst, &pair.line->b[sofs], min);
+ dst += min;
+ src++;
+ size -= min;
+ }
+
+ // (b) Copy subsequent cacheline sized chunks.
+ while (size >= CACHELINE_SIZE)
+ {
+ pair = this->write_lock(src, WaW);
+ *pair.mask = 0;
+ memcpy (dst, src, CACHELINE_SIZE);
+ dst += CACHELINE_SIZE;
+ src++;
+ size -= CACHELINE_SIZE;
+ }
+
+ // (c) Copy anything left over.
+ if (size != 0)
+ {
+ pair = this->write_lock(src, WaW);
+ *pair.mask &= ~(((gtm_cacheline_mask)1 << size) - 1);
+ memcpy (dst, pair.line, size);
+ }
+
+ // No need to drop locks, since we're going to abort the transaction
+ // anyhow.
+
+ return true;
+}
+
+
wbetl_dispatch::wbetl_dispatch ()
: gtm_dispatch (false, false)
{
===================================================================
@@ -42,6 +42,7 @@ class readonly_dispatch : public gtm_dis
virtual void rollback();
virtual void reinit();
virtual void fini();
+ virtual bool trydropreference (void *ptr, size_t size) { return true; }
};
inline
===================================================================
@@ -61,9 +61,11 @@ _ITM_free (void *ptr)
__attribute__((transaction_pure))
void ITM_REGPARM
-_ITM_dropReferences (const void *ptr, size_t len)
+_ITM_dropReferences (void *ptr, size_t len)
{
gtm_transaction *tx = gtm_tx();
+ if (!gtm_disp()->trydropreference (ptr, len))
+ tx->restart (RESTART_VALIDATE_READ);
tx->drop_references_local (ptr, len);
tx->drop_references_allocations (ptr);
}
===================================================================
@@ -153,7 +153,7 @@ extern void _ITM_addUserUndoAction(_ITM_
extern int _ITM_getThreadnum(void) ITM_REGPARM;
__attribute__((transaction_pure))
-extern void _ITM_dropReferences (const void *, size_t) ITM_REGPARM;
+extern void _ITM_dropReferences (void *, size_t) ITM_REGPARM;
/* The following typedefs exist to make the macro expansions below work
===================================================================
@@ -64,6 +64,7 @@ class serial_dispatch : public gtm_dispa
virtual void rollback() { abort(); }
virtual void reinit() { }
virtual void fini() { }
+ virtual bool trydropreference (void *ptr, size_t size) { return true; }
};
} // anon namespace
===================================================================
@@ -0,0 +1,35 @@
+#include <stdlib.h>
+#include <libitm.h>
+
+/* Test that _ITM_dropReferences() forces a commit of given chunk. */
+
+unsigned char pp[100];
+
+int main()
+{
+ int i;
+
+ for(i=0; i < 100; ++i)
+ pp[i]=0x22;
+
+ __transaction {
+ for(i=0; i < 100; ++i)
+ pp[i]=0x33;
+
+ /* This should write-through pp[0..49]... */
+ _ITM_dropReferences (pp, 50);
+
+ /* ...while this should revert everything but pp[0..49]. */
+ __transaction_cancel;
+ }
+
+ for(i=0; i < 50; ++i)
+ if (pp[i] != 0x33)
+ abort();
+
+ for(i=50; i < 100; ++i)
+ if (pp[i] != 0x22)
+ abort();
+
+ return 0;
+}
===================================================================
@@ -114,6 +114,7 @@ struct gtm_dispatch
virtual bool trycommit() = 0;
virtual void rollback() = 0;
virtual void reinit() = 0;
+ virtual bool trydropreference(void *, size_t) = 0;
// Use fini instead of dtor to support a static subclasses that uses
// a unique object and so we don't want to destroy it from common code.