]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/Monitor.cpp
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_transform / lib / Monitor.cpp
1 #include "Monitor.h"
2 #include <Block.h>
3 #include "misc.h"
4 #include "GroupTransform.h"
5 #include "Utilities.h"
6
7 void Monitor::Wait()
8 {
9 }
10
11
12
13 bool Monitor::IsExternalizable()
14 {
15 return false; // monitors aren't really part of the transform
16 }
17
18 void 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
71 BlockMonitor::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
86 BlockMonitor::~BlockMonitor()
87 {
88 Block_release(mBlock);
89 }
90
91 void 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
105 CFTypeRef BlockMonitor::Make(dispatch_queue_t queue, SecMessageBlock block)
106 {
107 return CoreFoundationHolder::MakeHolder(gInternalCFObjectName, new BlockMonitor(queue, block));
108 }