1#include "Monitor.h" 2#include <Block.h> 3#include "misc.h" 4#include "GroupTransform.h" 5#include "Utilities.h" 6 7void Monitor::Wait() 8{ 9} 10 11 12 13bool Monitor::IsExternalizable() 14{ 15 return false; // monitors aren't really part of the transform 16} 17 18void BlockMonitor::AttributeChanged(CFStringRef name, CFTypeRef value) 19{ 20 // deliver the attribute to the queue 21 CFTypeRef realValue = value; 22 CFErrorRef error = NULL; 23 bool isFinal = false; 24 25 if (mSeenFinal) 26 { 27 // A NULL and CFErrorRef might both be enqueued already, and the 2nd can race the teardown. Without this check we would trigger final processing 28 // more then once resulting in our own overlease issues, and could well cause our client to make similar errors. 29 return; 30 } 31 32 if (realValue != NULL) 33 { 34 // do some basic checking 35 if (CFGetTypeID(value) == CFErrorGetTypeID()) 36 { 37 realValue = NULL; 38 error = (CFErrorRef) value; 39 isFinal = true; 40 } 41 } 42 else 43 { 44 isFinal = true; 45 } 46 47 mSeenFinal = isFinal; 48 49 if (realValue) 50 { 51 CFRetain(realValue); 52 } 53 54 if (mDispatchQueue == NULL) 55 { 56 mBlock(realValue, error, isFinal); 57 } 58 else 59 { 60 // ^{ mBlock } gets referenced via this (no retain), localBlock gets owned by 61 // the block passed to dispatch_async 62 SecMessageBlock localBlock = mBlock; 63 dispatch_async(mDispatchQueue, ^{ 64 localBlock(realValue, error, isFinal); 65 }); 66 } 67} 68 69 70 71BlockMonitor::BlockMonitor(dispatch_queue_t queue, SecMessageBlock block) : Monitor(CFSTR("BlockMonitor")), mDispatchQueue(queue), mSeenFinal(FALSE) 72{ 73 mBlock = ^(CFTypeRef value, CFErrorRef error, Boolean isFinal) { 74 block(value, error, isFinal); 75 if (value) 76 { 77 CFRelease(value); 78 } 79 if (isFinal && mGroup) { 80 LastValueSent(); 81 } 82 }; 83 mBlock = Block_copy(mBlock); 84} 85 86BlockMonitor::~BlockMonitor() 87{ 88 Block_release(mBlock); 89} 90 91void BlockMonitor::LastValueSent() 92{ 93 // The initial execute did a retain on our parent to keep it from 94 // going out of scope. Since this chain is now done, release it. 95 // NOTE: this needs to be the last thing we do otherwise *this 96 // can be deleted out from under us, leading to a crash most frequently 97 // inside the block we dispatch_async, sometimes inside of mBlock. 98 Transform *rootGroup = this->GetRootGroup(); 99 CFTypeRef rootGroupRef = rootGroup->GetCFObject(); 100 dispatch_async(rootGroup->mDispatchQueue, ^{ 101 CFRelease(rootGroupRef); 102 }); 103} 104 105CFTypeRef BlockMonitor::Make(dispatch_queue_t queue, SecMessageBlock block) 106{ 107 return CoreFoundationHolder::MakeHolder(gInternalCFObjectName, new BlockMonitor(queue, block)); 108} 109