Index: runtime/vm/simulator_mips.cc |
=================================================================== |
--- runtime/vm/simulator_mips.cc (revision 41327) |
+++ runtime/vm/simulator_mips.cc (working copy) |
@@ -16,6 +16,7 @@ |
#include "vm/assembler.h" |
#include "vm/constants_mips.h" |
#include "vm/disassembler.h" |
+#include "vm/lockers.h" |
#include "vm/native_arguments.h" |
#include "vm/thread.h" |
@@ -558,7 +559,16 @@ |
} |
+// Synchronization primitives support. |
+Mutex* Simulator::exclusive_access_lock_ = NULL; |
+Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = |
+ {{NULL, 0}}; |
+int Simulator::next_address_tag_ = 0; |
+ |
+ |
void Simulator::InitOnce() { |
+ // Setup exclusive access state lock. |
+ exclusive_access_lock_ = new Mutex(); |
} |
@@ -943,6 +953,97 @@ |
} |
+// Synchronization primitives support. |
+void Simulator::SetExclusiveAccess(uword addr) { |
+ Isolate* isolate = Isolate::Current(); |
+ ASSERT(isolate != NULL); |
+ ASSERT(exclusive_access_lock_->Owner() == isolate); |
+ int i = 0; |
+ // Find an entry for this isolate in the exclusive access state. |
+ while ((i < kNumAddressTags) && |
+ (exclusive_access_state_[i].isolate != isolate)) { |
+ i++; |
+ } |
+ // Round-robin replacement of previously used entries. |
+ if (i == kNumAddressTags) { |
+ i = next_address_tag_; |
+ if (++next_address_tag_ == kNumAddressTags) { |
+ next_address_tag_ = 0; |
+ } |
+ exclusive_access_state_[i].isolate = isolate; |
+ } |
+ // Remember the address being reserved. |
+ exclusive_access_state_[i].addr = addr; |
+} |
+ |
+ |
+bool Simulator::HasExclusiveAccessAndOpen(uword addr) { |
+ Isolate* isolate = Isolate::Current(); |
+ ASSERT(isolate != NULL); |
+ ASSERT(addr != 0); |
+ ASSERT(exclusive_access_lock_->Owner() == isolate); |
+ bool result = false; |
+ for (int i = 0; i < kNumAddressTags; i++) { |
+ if (exclusive_access_state_[i].isolate == isolate) { |
+ // Check whether the current isolates address reservation matches. |
+ if (exclusive_access_state_[i].addr == addr) { |
+ result = true; |
+ } |
+ exclusive_access_state_[i].addr = 0; |
+ } else if (exclusive_access_state_[i].addr == addr) { |
+ // Other isolates with matching address lose their reservations. |
+ exclusive_access_state_[i].addr = 0; |
+ } |
+ } |
+ return result; |
+} |
+ |
+ |
+void Simulator::ClearExclusive() { |
+ MutexLocker ml(exclusive_access_lock_); |
+ // Remove the reservation for this isolate. |
+ SetExclusiveAccess(NULL); |
+} |
+ |
+ |
+intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { |
+ MutexLocker ml(exclusive_access_lock_); |
+ SetExclusiveAccess(addr); |
+ return ReadW(addr, instr); |
+} |
+ |
+ |
+intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { |
+ MutexLocker ml(exclusive_access_lock_); |
+ bool write_allowed = HasExclusiveAccessAndOpen(addr); |
+ if (write_allowed) { |
+ WriteW(addr, value, instr); |
+ return 0; // Success. |
+ } |
+ return 1; // Failure. |
+} |
+ |
+ |
+uword Simulator::CompareExchange(uword* address, |
+ uword compare_value, |
+ uword new_value) { |
+ MutexLocker ml(exclusive_access_lock_); |
+ // We do not get a reservation as it would be guaranteed to be found when |
+ // writing below. No other isolate is able to make a reservation while we |
+ // hold the lock. |
+ uword value = *address; |
+ if (value == compare_value) { |
+ *address = new_value; |
+ // Same effect on exclusive access state as a successful SC. |
+ HasExclusiveAccessAndOpen(reinterpret_cast<uword>(address)); |
+ } else { |
+ // Same effect on exclusive access state as an LL. |
+ SetExclusiveAccess(reinterpret_cast<uword>(address)); |
+ } |
+ return value; |
+} |
+ |
+ |
bool Simulator::OverflowFrom(int32_t alu_out, |
int32_t left, int32_t right, bool addition) { |
bool overflow; |