INT32 EFIAPI TestAndClearBit ( IN INT32 Bit, IN VOID *Address ) { UINT16 Word, Read; UINT16 Mask; // // Calculate the effective address relative to 'Address' based on the // higher order bits of 'Bit'. Use signed shift instead of division to // ensure we round towards -Inf, and end up with a positive shift in // 'Bit', even if 'Bit' itself is negative. // Address += (Bit >> 4) * sizeof(UINT16); Mask = 1U << (Bit & 15); for (Word = *(UINT16 *) Address; Word & Mask; Word = Read) { Read = InterlockedCompareExchange16 (Address, Word, Word & ~Mask); if (Read == Word) { return 1; } } return 0; }
static NTSTATUS GnttabRevokeForeignAccess( IN PINTERFACE Interface, IN PXENBUS_GNTTAB_CACHE Cache, IN BOOLEAN Locked, IN PXENBUS_GNTTAB_ENTRY Entry ) { PXENBUS_GNTTAB_CONTEXT Context = Interface->Context; volatile SHORT *flags; ULONG Attempt; NTSTATUS status; ASSERT3U(Entry->Magic, ==, XENBUS_GNTTAB_ENTRY_MAGIC); ASSERT3U(Entry->Reference, >=, XENBUS_GNTTAB_RESERVED_ENTRY_COUNT); ASSERT3U(Entry->Reference, <, (Context->FrameIndex + 1) * XENBUS_GNTTAB_ENTRY_PER_FRAME); flags = (volatile SHORT *)&Context->Table[Entry->Reference].flags; Attempt = 0; while (Attempt++ < 100) { uint16_t Old; uint16_t New; Old = *flags; Old &= ~(GTF_reading | GTF_writing); New = Old & ~GTF_permit_access; if (InterlockedCompareExchange16(flags, New, Old) == Old) break; SchedYield(); } status = STATUS_UNSUCCESSFUL; if (Attempt == 100) goto fail1; RtlZeroMemory(&Context->Table[Entry->Reference], sizeof (grant_entry_v1_t)); RtlZeroMemory(&Entry->Entry, sizeof (grant_entry_v1_t)); XENBUS_CACHE(Put, &Context->CacheInterface, Cache->Cache, Entry, Locked); return STATUS_SUCCESS; fail1: Error("fail1 (%08x)\n", status); return status; }
static NTSTATUS GnttabRevokeForeignAccess( IN PXENBUS_GNTTAB_CONTEXT Context, IN PXENBUS_GNTTAB_CACHE Cache, IN BOOLEAN Locked, IN PXENBUS_GNTTAB_DESCRIPTOR Descriptor ) { grant_entry_v1_t *Entry; volatile SHORT *Flags; ULONG Attempt; NTSTATUS status; ASSERT3U(Descriptor->Magic, ==, GNTTAB_DESCRIPTOR_MAGIC); ASSERT3U(Descriptor->Reference, >=, GNTTAB_RESERVED_ENTRY_COUNT); ASSERT3U(Descriptor->Reference, <, (Context->FrameIndex + 1) * GNTTAB_ENTRY_PER_FRAME); Entry = &Context->Entry[Descriptor->Reference]; Flags = (volatile SHORT *)&Entry->flags; Attempt = 0; while (Attempt++ < 100) { uint16_t Old; uint16_t New; Old = *Flags; Old &= ~(GTF_reading | GTF_writing); New = Old & ~GTF_permit_access; if (InterlockedCompareExchange16(Flags, New, Old) == Old) break; SchedYield(); } status = STATUS_UNSUCCESSFUL; if (Attempt == 100) goto fail1; RtlZeroMemory(Entry, sizeof (grant_entry_v1_t)); RtlZeroMemory(&Descriptor->Entry, sizeof (grant_entry_v1_t)); CACHE(Put, Context->CacheInterface, Cache->Cache, Descriptor, Locked); return STATUS_SUCCESS; fail1: Error("fail1 (%08x)\n", status); return status; }
bool trySet(Type *p, Type newVal, Type oldVal) { bool success = false; #if defined(X_MSVC) xAssertIsSpecificAligned(p, 8); // try to lock the updating flag, if we cant, someone else is working. success = InterlockedCompareExchange16(p, newVal, oldVal) == oldVal; #else success = __sync_val_compare_and_swap(p, oldVal, newVal) == oldVal; #endif return success; }