1/*
2 * Copyright (c) 2000-2001,2004,2009 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// structure - structural framework for securityd objects
27//
28#include "structure.h"
29
30
31//
32// NodeCore always has a destructor (because it's virtual),
33// but its dump support is conditionally included.
34//
35NodeCore::~NodeCore()
36{
37#if defined(DEBUGDUMP)
38	StLock<Mutex> _(mCoreLock);
39	mCoreNodes.erase(this);
40#endif //DEBUGDUMP
41}
42
43
44//
45// Basic object mesh maintainance
46//
47void NodeCore::parent(NodeCore &p)
48{
49	StLock<Mutex> _(*this);
50	mParent = &p;
51}
52
53void NodeCore::referent(NodeCore &r)
54{
55	StLock<Mutex> _(*this);
56	assert(!mReferent);
57	mReferent = &r;
58}
59
60void NodeCore::clearReferent()
61{
62	StLock<Mutex> _(*this);
63	if (mReferent)
64		assert(!mReferent->hasReference(*this));
65	mReferent = NULL;
66}
67
68
69void NodeCore::addReference(NodeCore &p)
70{
71	StLock<Mutex> _(*this);
72	assert(p.mReferent == this);
73	mReferences.insert(&p);
74}
75
76void NodeCore::removeReference(NodeCore &p)
77{
78	StLock<Mutex> _(*this);
79	assert(hasReference(p));
80	mReferences.erase(&p);
81}
82
83#if !defined(NDEBUG)
84
85bool NodeCore::hasReference(NodeCore &p)
86{
87	assert(p.refCountForDebuggingOnly() > 0);
88	return mReferences.find(&p) != mReferences.end();
89}
90
91#endif //NDEBUG
92
93
94//
95// ClearReferences clears the reference set but does not propagate
96// anything; it is NOT recursive.
97//
98void NodeCore::clearReferences()
99{
100	StLock<Mutex> _(*this);
101	secdebug("ssnode", "%p clearing all %d references",
102		this, int(mReferences.size()));
103	mReferences.erase(mReferences.begin(), mReferences.end());
104}
105
106
107//
108// Kill should be overloaded by Nodes to implement any cleanup and release
109// operations that should happen at LOGICAL death of the represented object.
110// This is where you should release ports, close files, etc.
111// This default behavior, which you MUST include in your override,
112// propagates kills to all active references, recursively.
113//
114void NodeCore::kill()
115{
116	StLock<Mutex> _(*this);
117	for (ReferenceSet::const_iterator it = mReferences.begin(); it != mReferences.end(); it++)
118		(*it)->kill();
119	clearReferences();
120}
121
122
123void NodeCore::kill(NodeCore &ref)
124{
125	StLock<Mutex> _(*this);
126	assert(hasReference(ref));
127	ref.kill();
128	removeReference(ref);
129}
130
131
132//
133// NodeCore-level support for state dumping.
134// Call NodeCore::dumpAll() to debug-dump all nodes.
135// Note that enabling DEBUGDUMP serializes all node creation/destruction
136// operations, and thus may cause significant shifts in thread interactions.
137//
138#if defined(DEBUGDUMP)
139
140// The (uncounted) set of all known NodeCores in existence, with protective lock
141set<NodeCore *> NodeCore::mCoreNodes;
142Mutex NodeCore::mCoreLock;
143
144// add a new NodeCore to the known set
145NodeCore::NodeCore()
146	: Mutex(Mutex::recursive)
147{
148	StLock<Mutex> _(mCoreLock);
149	mCoreNodes.insert(this);
150}
151
152// partial-line common dump text for any NodeCore
153// override this to add text to your Node type's state dump output
154void NodeCore::dumpNode()
155{
156 Debug::dump("%s@%p rc=%u", Debug::typeName(*this).c_str(), this, unsigned(refCountForDebuggingOnly()));
157	if (mParent)
158		Debug::dump(" parent=%p", mParent.get());
159	if (mReferent)
160		Debug::dump(" referent=%p", mReferent.get());
161}
162
163// full-line dump of a NodeCore
164// override this to completely re-implement the dump format for your Node type
165void NodeCore::dump()
166{
167 dumpNode();
168	if (!mReferences.empty()) {
169		Debug::dump(" {");
170		for (ReferenceSet::const_iterator it = mReferences.begin(); it != mReferences.end(); it++) {
171			Debug::dump(" %p", it->get());
172			if ((*it)->mReferent != this)
173				Debug::dump("!*INVALID*");
174		}
175		Debug::dump(" }");
176	}
177	Debug::dump("\n");
178}
179
180// dump all known nodes
181void NodeCore::dumpAll()
182{
183 StLock<Mutex> _(mCoreLock);
184	time_t now; time(&now);
185	Debug::dump("\nNODE DUMP (%24.24s)\n", ctime(&now));
186	for (set<NodeCore *>::const_iterator it = mCoreNodes.begin(); it != mCoreNodes.end(); it++)
187		(*it)->dump();
188	Debug::dump("END NODE DUMP\n\n");
189}
190
191#endif //DEBUGDUMP
192