Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Patching TPCircularBuffer based on suggestion from landonf and maqr

  • Loading branch information...
commit 655ea5e8991a2ac5030de702dae1c4864460e4e5 1 parent fc26b00
@jweinberg jweinberg authored
Showing with 57 additions and 41 deletions.
  1. +57 −41 OpenEmu/TPCircularBuffer.c
View
98 OpenEmu/TPCircularBuffer.c
@@ -38,48 +38,64 @@ static inline bool _checkResult(kern_return_t result, const char *operation, con
}
bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) {
- assert(length);
- buffer->length = round_page(length); // We need whole page sizes
-
- // Temporarily allocate twice the length, so we have the contiguous address space to
- // support a second instance of the buffer directly after
- vm_address_t bufferAddress;
- if ( !checkResult(vm_allocate(mach_task_self(), &bufferAddress, buffer->length * 2, TRUE /* (don't use the current bufferAddress value) */),
- "Buffer allocation") ) return false;
-
- // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half...
- if ( !checkResult(vm_deallocate(mach_task_self(), bufferAddress + buffer->length, buffer->length),
- "Buffer deallocation") ) return false;
-
- // Then create a memory entry that refers to the buffer
- vm_size_t entry_length = buffer->length;
- mach_port_t memoryEntry;
- if ( !checkResult(mach_make_memory_entry(mach_task_self(), &entry_length, bufferAddress, VM_PROT_READ|VM_PROT_WRITE, &memoryEntry, 0),
- "Create memory entry") ) {
- vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
- return false;
- }
-
- // And map the memory entry to the address space immediately after the buffer
- vm_address_t virtualAddress = bufferAddress + buffer->length;
- if ( !checkResult(vm_map(mach_task_self(), &virtualAddress, buffer->length, 0, FALSE, memoryEntry, 0, FALSE, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_DEFAULT),
- "Map buffer memory") ) {
- vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
- return false;
- }
-
- if ( virtualAddress != bufferAddress+buffer->length ) {
- printf("Couldn't map buffer memory to end of buffer\n");
- vm_deallocate(mach_task_self(), virtualAddress, buffer->length);
- vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
- return false;
+ // keep trying tuntil we get our buffer, needed to handle race conditions
+ while(1) {
+ buffer->length = round_page(length); // We need whole page sizes
+ // Temporarily allocate twice the length, so we have the contiguous address space to
+ // support a second instance of the buffer directly after
+ vm_address_t bufferAddress;
+ if ( !checkResult(vm_allocate(mach_task_self(),
+ &bufferAddress,
+ buffer->length * 2,
+ VM_FLAGS_ANYWHERE), // allocate anywhere it'll fit
+ "Buffer allocation") ) {
+ // try again if we fail
+ continue;
+ }
+
+ // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half...
+ if ( !checkResult(vm_deallocate(mach_task_self(),
+ bufferAddress + buffer->length,
+ buffer->length),
+ "Buffer deallocation") ) {
+ // if this fails somehow, deallocate the whole region and try again
+ vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
+ continue;
+ }
+
+ // Re-map the buffer to the address space immediately after the buffer
+ vm_address_t virtualAddress = bufferAddress + buffer->length;
+ vm_prot_t cur_prot, max_prot;
+ if(!checkResult(vm_remap(mach_task_self(),
+ &virtualAddress, // mirror target
+ buffer->length, // size of mirror
+ 0, // auto alignment
+ 0, // force remapping to virtualAddress
+ mach_task_self(), // same task
+ bufferAddress, // mirror source
+ 0, // MAP READ-WRITE, NOT COPY
+ &cur_prot, // unused protection struct
+ &max_prot, // unused protection struct
+ VM_INHERIT_DEFAULT), "Remap buffer memory")) {
+ // if this remap failed, we hit a race condition, so deallocate and try again
+ vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
+ continue;
+ }
+
+ if ( virtualAddress != bufferAddress+buffer->length ) {
+ // if the memory is not contiguous, clean up both allocated buffers and try again
+ printf("Couldn't map buffer memory to end of buffer\n");
+ vm_deallocate(mach_task_self(), virtualAddress, buffer->length);
+ vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
+ continue;
+ }
+
+ buffer->buffer = (void*)bufferAddress;
+ buffer->fillCount = 0;
+ buffer->head = buffer->tail = 0;
+
+ return true;
}
-
- buffer->buffer = (void*)bufferAddress;
- buffer->fillCount = 0;
- buffer->head = buffer->tail = 0;
-
- return true;
}
void TPCircularBufferCleanup(TPCircularBuffer *buffer) {

0 comments on commit 655ea5e

Please sign in to comment.
Something went wrong with that request. Please try again.