3 // Circular/Ring buffer implementation
5 // Created by Michael Tyson on 10/12/2011.
6 // Copyright 2011-2012 A Tasty Pixel. All rights reserved.
9 #include "audio_output/TPCircularBuffer.h"
10 #include <mach/mach.h>
13 #define reportResult(result,operation) (_reportResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
14 static inline bool _reportResult(kern_return_t result
, const char *operation
, const char* file
, int line
) {
15 if ( result
!= ERR_SUCCESS
) {
16 printf("%s:%d: %s: %s\n", file
, line
, operation
, mach_error_string(result
));
22 bool TPCircularBufferInit(TPCircularBuffer
*buffer
, int length
) {
24 // Keep trying until we get our buffer, needed to handle race conditions
28 buffer
->length
= round_page(length
); // We need whole page sizes
30 // Temporarily allocate twice the length, so we have the contiguous address space to
31 // support a second instance of the buffer directly after
32 vm_address_t bufferAddress
;
33 kern_return_t result
= vm_allocate(mach_task_self(),
36 VM_FLAGS_ANYWHERE
); // allocate anywhere it'll fit
37 if ( result
!= ERR_SUCCESS
) {
38 if ( retries
-- == 0 ) {
39 reportResult(result
, "Buffer allocation");
42 // Try again if we fail
46 // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half...
47 result
= vm_deallocate(mach_task_self(),
48 bufferAddress
+ buffer
->length
,
50 if ( result
!= ERR_SUCCESS
) {
51 if ( retries
-- == 0 ) {
52 reportResult(result
, "Buffer deallocation");
55 // If this fails somehow, deallocate the whole region and try again
56 vm_deallocate(mach_task_self(), bufferAddress
, buffer
->length
);
60 // Re-map the buffer to the address space immediately after the buffer
61 vm_address_t virtualAddress
= bufferAddress
+ buffer
->length
;
62 vm_prot_t cur_prot
, max_prot
;
63 result
= vm_remap(mach_task_self(),
64 &virtualAddress
, // mirror target
65 buffer
->length
, // size of mirror
67 0, // force remapping to virtualAddress
68 mach_task_self(), // same task
69 bufferAddress
, // mirror source
70 0, // MAP READ-WRITE, NOT COPY
71 &cur_prot
, // unused protection struct
72 &max_prot
, // unused protection struct
74 if ( result
!= ERR_SUCCESS
) {
75 if ( retries
-- == 0 ) {
76 reportResult(result
, "Remap buffer memory");
79 // If this remap failed, we hit a race condition, so deallocate and try again
80 vm_deallocate(mach_task_self(), bufferAddress
, buffer
->length
);
84 if ( virtualAddress
!= bufferAddress
+buffer
->length
) {
85 // If the memory is not contiguous, clean up both allocated buffers and try again
86 if ( retries
-- == 0 ) {
87 printf("Couldn't map buffer memory to end of buffer\n");
91 vm_deallocate(mach_task_self(), virtualAddress
, buffer
->length
);
92 vm_deallocate(mach_task_self(), bufferAddress
, buffer
->length
);
96 buffer
->buffer
= (void*)bufferAddress
;
97 buffer
->fillCount
= 0;
98 buffer
->head
= buffer
->tail
= 0;
105 void TPCircularBufferCleanup(TPCircularBuffer
*buffer
) {
106 vm_deallocate(mach_task_self(), (vm_address_t
)buffer
->buffer
, buffer
->length
* 2);
107 memset(buffer
, 0, sizeof(TPCircularBuffer
));
110 void TPCircularBufferClear(TPCircularBuffer
*buffer
) {
112 if ( TPCircularBufferTail(buffer
, &fillCount
) ) {
113 TPCircularBufferConsume(buffer
, fillCount
);