]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/Monitor.cpp
Security-59754.80.3.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 CFRetainSafe(realValue);
50
51 if (mDispatchQueue == NULL)
52 {
53 mBlock(realValue, error, isFinal);
54 }
55 else
56 {
57 // ^{ mBlock } gets referenced via this (no retain), localBlock gets owned by
58 // the block passed to dispatch_async
59 SecMessageBlock localBlock = mBlock;
60 dispatch_async(mDispatchQueue, ^{
61 localBlock(realValue, error, isFinal);
62 });
63 }
64 }
65
66
67
68 BlockMonitor::BlockMonitor(dispatch_queue_t queue, SecMessageBlock block) : Monitor(CFSTR("BlockMonitor")), mDispatchQueue(queue), mSeenFinal(FALSE)
69 {
70 mBlock = ^(CFTypeRef value, CFErrorRef error, Boolean isFinal) {
71 block(value, error, isFinal);
72 if (value)
73 {
74 CFReleaseNull(value);
75 }
76 if (isFinal && mGroup) {
77 LastValueSent();
78 }
79 };
80 mBlock = Block_copy(mBlock);
81 }
82
83 BlockMonitor::~BlockMonitor()
84 {
85 Block_release(mBlock);
86 }
87
88 void BlockMonitor::LastValueSent()
89 {
90 // The initial execute did a retain on our parent to keep it from
91 // going out of scope. Since this chain is now done, release it.
92 // NOTE: this needs to be the last thing we do otherwise *this
93 // can be deleted out from under us, leading to a crash most frequently
94 // inside the block we dispatch_async, sometimes inside of mBlock.
95 Transform *rootGroup = this->GetRootGroup();
96 CFTypeRef rootGroupRef = rootGroup->GetCFObject();
97 dispatch_async(rootGroup->mDispatchQueue, ^{
98 CFReleaseSafe(rootGroupRef);
99 });
100 }
101
102 CFTypeRef BlockMonitor::Make(dispatch_queue_t queue, SecMessageBlock block)
103 {
104 return CoreFoundationHolder::MakeHolder(gInternalCFObjectName, new BlockMonitor(queue, block));
105 }