1/*
2 *  IOFWUserObjectExporter.cpp
3 *  IOFireWireFamily
4 *
5 *  Created by Niels on Mon Apr 14 2003.
6 *  Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
7 *
8 *	$Log: IOFWUserObjectExporter.cpp,v $
9 *	Revision 1.19  2008/05/08 02:33:21  collin
10 *	more K64
11 *
12 *	Revision 1.18  2008/05/06 03:26:57  collin
13 *	more K64
14 *
15 *	Revision 1.17  2008/04/30 03:02:13  collin
16 *	publicize the exporter
17 *
18 *	Revision 1.16  2008/04/11 00:52:37  collin
19 *	some K64 changes
20 *
21 *	Revision 1.15  2007/03/14 01:01:12  collin
22 *	*** empty log message ***
23 *
24 *	Revision 1.14  2006/02/09 00:21:51  niels
25 *	merge chardonnay branch to tot
26 *
27 *	Revision 1.13  2005/09/24 00:55:28  niels
28 *	*** empty log message ***
29 *
30 *	Revision 1.12  2005/04/12 20:09:13  niels
31 *	fix memory leak importing NuDCL programs from user space
32 *
33 *	Revision 1.11  2005/04/02 02:43:46  niels
34 *	exporter works outside IOFireWireFamily
35 *
36 *	Revision 1.10  2005/03/31 02:31:44  niels
37 *	more object exporter fixes
38 *
39 *	Revision 1.9  2005/03/30 22:14:55  niels
40 *	Fixed compile errors see on Tiger w/ GCC 4.0
41 *	Moved address-of-member-function calls to use OSMemberFunctionCast
42 *	Added owner field to IOFWUserObjectExporter
43 *	User client now cleans up published unit directories when client dies
44 *
45 *	Revision 1.8.18.3  2006/01/31 04:49:50  collin
46 *	*** empty log message ***
47 *
48 *	Revision 1.8.18.1  2005/07/23 00:30:44  collin
49 *	*** empty log message ***
50 *
51 *	Revision 1.8  2003/12/18 00:08:12  niels
52 *	fix panic calling methods on deallocated user objects
53 *
54 *	Revision 1.7  2003/12/15 23:31:32  niels
55 *	fix object exporter panic when passed NULL object handle
56 *
57 *	Revision 1.6  2003/11/20 21:32:58  niels
58 *	fix radar 3490815
59 *
60 *	Revision 1.5  2003/08/30 00:16:44  collin
61 *	*** empty log message ***
62 *
63 *	Revision 1.4  2003/08/27 19:27:04  niels
64 *	*** empty log message ***
65 *
66 *	Revision 1.3  2003/08/08 22:30:32  niels
67 *	*** empty log message ***
68 *
69 *	Revision 1.2  2003/07/21 06:52:59  niels
70 *	merge isoch to TOT
71 *
72 *	Revision 1.1.2.1  2003/07/01 20:54:07  niels
73 *	isoch merge
74 *
75 */
76
77#undef min
78#undef max
79
80#import <sys/systm.h>   // for snprintf...
81
82#import "IOFWUserObjectExporter.h"
83#import "FWDebugging.h"
84
85#undef super
86#define super OSObject
87
88OSDefineMetaClassAndStructors ( IOFWUserObjectExporter, super );
89
90OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 0);
91OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 1);
92OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 2);
93OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 3);
94OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 4);
95OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 5);
96OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 6);
97OSMetaClassDefineReservedUnused(IOFWUserObjectExporter, 7);
98
99// createWithOwner
100//
101// static factory method
102
103IOFWUserObjectExporter * IOFWUserObjectExporter::createWithOwner( OSObject * owner )
104{
105	DebugLog( "IOFWUserObjectExporter::create\n" );
106
107	bool success = true;
108
109	IOFWUserObjectExporter * object = NULL;
110
111	object = OSTypeAlloc( IOFWUserObjectExporter );
112	if( object == NULL )
113	{
114		success = false;
115	}
116
117	if( success )
118	{
119		success = object->initWithOwner( owner );
120	}
121
122	if( !success )
123	{
124		if( object )
125		{
126			object->release();
127			object = NULL;
128		}
129	}
130
131	return object;
132}
133
134bool
135IOFWUserObjectExporter::init()
136{
137	fLock = IOLockAlloc () ;
138	if ( ! fLock )
139		return false ;
140
141	return super::init () ;
142}
143
144bool
145IOFWUserObjectExporter::initWithOwner ( OSObject * owner )
146{
147	fOwner = owner ;
148
149	return init() ;
150}
151
152void
153IOFWUserObjectExporter::free ()
154{
155	DebugLog( "free object exporter %p, fObjectCount = %d\n", this, fObjectCount ) ;
156
157	removeAllObjects () ;
158
159	if ( fLock )
160		IOLockFree( fLock ) ;
161
162	fOwner = NULL ;
163
164	super::free () ;
165}
166
167bool
168IOFWUserObjectExporter::serialize (
169	OSSerialize * s ) const
170{
171	lock() ;
172
173	const OSString * keys[ 3 ] =
174	{
175		OSString::withCString( "capacity" )
176		, OSString::withCString( "used" )
177		, OSString::withCString( "objects" )
178	} ;
179
180	const OSObject * objects[ 3 ] =
181	{
182		OSNumber::withNumber( (unsigned long long)fCapacity, 32 )
183		, OSNumber::withNumber( (unsigned long long)fObjectCount, 32 )
184		, fObjects ? OSArray::withObjects( fObjects, fObjectCount ) : OSArray::withCapacity(0)
185	} ;
186
187	OSDictionary * dict = OSDictionary::withObjects( objects, keys, sizeof( keys ) / sizeof( OSObject* ) ) ;
188
189	if ( !dict )
190	{
191		unlock() ;
192		return false ;
193	}
194
195	bool result = dict->serialize( s ) ;
196
197	unlock() ;
198
199	return result ;
200}
201
202IOReturn
203IOFWUserObjectExporter::addObject ( OSObject * obj, CleanupFunction cleanupFunction, IOFireWireLib::UserObjectHandle * outHandle )
204{
205	IOReturn error = kIOReturnSuccess ;
206
207	lock () ;
208
209	if ( ! fObjects )
210	{
211		fCapacity = 8 ;
212		fObjects = (const OSObject **) new const OSObject * [ fCapacity ] ;
213		fCleanupFunctions = new CleanupFunctionWithExporter[ fCapacity ] ;
214
215		if ( ! fObjects || !fCleanupFunctions )
216		{
217			DebugLog( "Couldn't make fObjects\n" ) ;
218			error = kIOReturnNoMemory ;
219		}
220	}
221
222	// if at capacity, expand pool
223	if ( fObjectCount == fCapacity )
224	{
225		unsigned newCapacity = fCapacity + ( fCapacity >> 1 ) ;
226		if ( newCapacity > 0xFFFE )
227			newCapacity = 0xFFFE ;
228
229		if ( newCapacity == fCapacity )	// can't grow!
230		{
231			DebugLog( "Can't grow object exporter\n" ) ;
232			error = kIOReturnNoMemory ;
233		}
234
235		const OSObject ** newObjects = NULL ;
236		CleanupFunctionWithExporter * newCleanupFunctions = NULL ;
237
238		if ( ! error )
239		{
240			newObjects = (const OSObject **) new OSObject * [ newCapacity ] ;
241
242			if ( !newObjects )
243				error = kIOReturnNoMemory ;
244		}
245
246		if ( !error )
247		{
248			newCleanupFunctions = new CleanupFunctionWithExporter[ newCapacity ] ;
249			if ( !newCleanupFunctions )
250				error = kIOReturnNoMemory ;
251		}
252
253		if ( ! error )
254		{
255			bcopy ( fObjects, newObjects, fCapacity * sizeof ( OSObject * ) ) ;
256			delete[] fObjects ;
257
258			bcopy ( fCleanupFunctions, newCleanupFunctions, fCapacity * sizeof( CleanupFunction * ) ) ;
259			delete[] fCleanupFunctions ;
260
261			fObjects = newObjects ;
262			fCleanupFunctions = newCleanupFunctions ;
263			fCapacity = newCapacity ;
264		}
265	}
266
267	if ( ! error )
268	{
269		error = kIOReturnNoMemory ;
270		unsigned index = 0 ;
271
272		while ( index < fCapacity )
273		{
274			if ( ! fObjects [ index ] )
275			{
276				obj->retain () ;
277				fObjects[ index ] = obj ;
278				fCleanupFunctions[ index ] = (CleanupFunctionWithExporter)cleanupFunction ;
279				*outHandle = (IOFireWireLib::UserObjectHandle)(index + 1) ;		// return index + 1; this means 0 is always an invalid/NULL index...
280				++fObjectCount ;
281				error = kIOReturnSuccess ;
282				break ;
283			}
284
285			++index ;
286		}
287	}
288
289	unlock () ;
290
291	ErrorLogCond( error, "fExporter->addObject returning error %x\n", error ) ;
292
293	return error ;
294}
295
296void
297IOFWUserObjectExporter::removeObject ( IOFireWireLib::UserObjectHandle handle )
298{
299	if ( !handle )
300	{
301		return ;
302	}
303
304	lock () ;
305
306	DebugLog("user object exporter removing handle %d\n", (uint32_t)handle);
307
308	unsigned index = (unsigned)handle - 1 ;		// handle is object's index + 1; this means 0 is always in invalid/NULL index...
309
310	const OSObject * object = NULL ;
311	CleanupFunctionWithExporter cleanupFunction = NULL ;
312
313	if ( fObjects && ( index < fCapacity ) )
314	{
315		if ( fObjects[ index ] )
316		{
317			DebugLog( "found object %p (%s), retain count=%d\n", fObjects[ index ], fObjects[ index ]->getMetaClass()->getClassName(), fObjects[ index ]->getRetainCount() );
318
319			object = fObjects[ index ] ;
320			fObjects[ index ] = NULL ;
321
322			cleanupFunction = fCleanupFunctions[ index ] ;
323			fCleanupFunctions[ index ] = NULL ;
324
325			--fObjectCount ;
326		}
327	}
328
329	unlock () ;
330
331	if ( object )
332	{
333		if ( cleanupFunction )
334		{
335			InfoLog("IOFWUserObjectExporter<%p>::removeObject() -- calling cleanup function for object %p of class %s\n", this, object, object->getMetaClass()->getClassName() ) ;
336			(*cleanupFunction)( object, this ) ;
337		}
338
339		object->release() ;
340	}
341
342}
343
344const IOFireWireLib::UserObjectHandle
345IOFWUserObjectExporter::lookupHandle ( OSObject * object ) const
346{
347	IOFireWireLib::UserObjectHandle	out_handle = 0;
348
349	if ( !object )
350	{
351		return NULL;
352	}
353
354	lock () ;
355
356	unsigned index = 0 ;
357
358	while ( index < fCapacity )
359	{
360		if( fObjects[index] == object )
361		{
362			out_handle = (IOFireWireLib::UserObjectHandle)(index + 1) ;		// return index + 1; this means 0 is always an invalid/NULL index...
363			break;
364		}
365
366		++index;
367	}
368
369	unlock ();
370
371	return out_handle;
372}
373
374const OSObject *
375IOFWUserObjectExporter::lookupObject ( IOFireWireLib::UserObjectHandle handle ) const
376{
377	if ( !handle )
378	{
379		return NULL ;
380	}
381
382	const OSObject * result = NULL ;
383
384	lock () ;
385
386	unsigned index = (unsigned)handle - 1 ;
387
388	if ( fObjects && ( index < fCapacity ) )
389	{
390		result = fObjects [ index ] ;
391		if ( result )
392		{
393			result->retain() ;
394		}
395	}
396
397	unlock () ;
398
399	return result ;
400}
401
402const OSObject *
403IOFWUserObjectExporter::lookupObjectForType( IOFireWireLib::UserObjectHandle handle, const OSMetaClass * toType ) const
404{
405	if( !handle )
406	{
407		return NULL;
408	}
409
410	const OSObject * result = NULL;
411
412	lock ();
413
414	unsigned index = (unsigned)handle - 1;
415
416	if ( fObjects && ( index < fCapacity ) )
417	{
418		result = fObjects [ index ];
419	}
420
421	if( result )
422	{
423		result = (OSObject*)OSMetaClassBase::safeMetaCast( result, toType );
424	}
425
426	if( result )
427	{
428		result->retain();
429	}
430
431	unlock ();
432
433	return result;
434}
435
436void
437IOFWUserObjectExporter::removeAllObjects ()
438{
439	lock () ;
440
441	const OSObject ** objects = NULL ;
442	CleanupFunctionWithExporter * cleanupFunctions = NULL ;
443
444	unsigned capacity = fCapacity ;
445
446	if ( fObjects )
447	{
448		objects = (const OSObject **)IOMalloc( sizeof(const OSObject *) * capacity ) ;
449		cleanupFunctions = (CleanupFunctionWithExporter*)IOMalloc( sizeof( CleanupFunctionWithExporter ) * capacity ) ;
450
451		if ( objects )
452			bcopy( fObjects, objects, sizeof( const OSObject * ) * capacity ) ;
453
454		if ( cleanupFunctions )
455			bcopy( fCleanupFunctions, cleanupFunctions, sizeof( CleanupFunction) * capacity ) ;
456
457		delete[] fObjects ;
458		fObjects = NULL ;
459
460		delete[] fCleanupFunctions ;
461		fCleanupFunctions = NULL ;
462
463		fObjectCount = 0 ;
464		fCapacity = 0 ;
465	}
466
467	unlock() ;
468
469	if ( objects && cleanupFunctions )
470	{
471		for ( unsigned index=0; index < capacity; ++index )
472		{
473			if ( objects[index] )
474			{
475				InfoLog("IOFWUserObjectExporter<%p>::removeAllObjects() -- remove object %p of class %s\n", this, objects[ index ], objects[ index ]->getMetaClass()->getClassName() ) ;
476
477				if ( cleanupFunctions[ index ] )
478				{
479					InfoLog("IOFWUserObjectExporter<%p>::removeAllObjects() -- calling cleanup function for object %p of type %s\n", this, objects[ index ], objects[ index ]->getMetaClass()->getClassName() ) ;
480					(*cleanupFunctions[ index ])( objects[ index ], this ) ;
481				}
482
483				objects[index]->release() ;
484			}
485		}
486
487		IOFree( objects, sizeof(const OSObject *) * capacity ) ;
488		IOFree( cleanupFunctions, sizeof( CleanupFunction ) * capacity ) ;
489	}
490}
491
492// getOwner
493//
494//
495
496OSObject *
497IOFWUserObjectExporter::getOwner() const
498{
499	return fOwner;
500}
501
502// lock
503//
504//
505
506void
507IOFWUserObjectExporter::lock( void ) const
508{
509	IOLockLock ( fLock );
510}
511
512// unlock
513//
514//
515
516void
517IOFWUserObjectExporter::unlock( void ) const
518{
519	IOLockUnlock ( fLock );
520}
521
522