xref: /xnu-12377.61.12/iokit/Tests/TestServices/TestIOServiceUserNotification.cpp (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1*4d495c6eSApple OSS Distributions #if DEVELOPMENT || DEBUG
2*4d495c6eSApple OSS Distributions #include "TestIOServiceUserNotification.h"
3*4d495c6eSApple OSS Distributions #include <IOKit/IOService.h>
4*4d495c6eSApple OSS Distributions #include <IOKit/IOUserClient.h>
5*4d495c6eSApple OSS Distributions #include <IOKit/IOKitServer.h>
6*4d495c6eSApple OSS Distributions #include <kern/ipc_kobject.h>
7*4d495c6eSApple OSS Distributions #include "../../Kernel/IOServicePrivate.h"
8*4d495c6eSApple OSS Distributions 
9*4d495c6eSApple OSS Distributions OSDefineMetaClassAndStructors(TestIOServiceUserNotification, IOService);
10*4d495c6eSApple OSS Distributions 
11*4d495c6eSApple OSS Distributions OSDefineMetaClassAndStructors(TestIOServiceUserNotificationUserClient, IOUserClient);
12*4d495c6eSApple OSS Distributions 
13*4d495c6eSApple OSS Distributions bool
start(IOService * provider)14*4d495c6eSApple OSS Distributions TestIOServiceUserNotification::start(IOService * provider)
15*4d495c6eSApple OSS Distributions {
16*4d495c6eSApple OSS Distributions 	OSString * str = OSString::withCStringNoCopy("TestIOServiceUserNotificationUserClient");
17*4d495c6eSApple OSS Distributions 	bool ret = IOService::start(provider);
18*4d495c6eSApple OSS Distributions 	if (ret && str != NULL) {
19*4d495c6eSApple OSS Distributions 		setProperty(gIOUserClientClassKey, str);
20*4d495c6eSApple OSS Distributions 		fUserNotifications = OSArray::withCapacity(1);
21*4d495c6eSApple OSS Distributions 		fLock = IOLockAlloc();
22*4d495c6eSApple OSS Distributions 		registerService();
23*4d495c6eSApple OSS Distributions 	}
24*4d495c6eSApple OSS Distributions 	OSSafeReleaseNULL(str);
25*4d495c6eSApple OSS Distributions 	return ret;
26*4d495c6eSApple OSS Distributions }
27*4d495c6eSApple OSS Distributions 
28*4d495c6eSApple OSS Distributions void
free()29*4d495c6eSApple OSS Distributions TestIOServiceUserNotification::free()
30*4d495c6eSApple OSS Distributions {
31*4d495c6eSApple OSS Distributions 	if (fLock) {
32*4d495c6eSApple OSS Distributions 		IOLockFree(fLock);
33*4d495c6eSApple OSS Distributions 		fLock = NULL;
34*4d495c6eSApple OSS Distributions 	}
35*4d495c6eSApple OSS Distributions 	OSSafeReleaseNULL(fUserNotifications);
36*4d495c6eSApple OSS Distributions 	IOService::free();
37*4d495c6eSApple OSS Distributions }
38*4d495c6eSApple OSS Distributions 
39*4d495c6eSApple OSS Distributions void
registerUserNotification(OSObject * notification)40*4d495c6eSApple OSS Distributions TestIOServiceUserNotification::registerUserNotification(OSObject * notification)
41*4d495c6eSApple OSS Distributions {
42*4d495c6eSApple OSS Distributions 	IOLockLock(fLock);
43*4d495c6eSApple OSS Distributions 	// Proactively trim the list to avoid holding too many objects
44*4d495c6eSApple OSS Distributions 	trimUserNotificationsLocked();
45*4d495c6eSApple OSS Distributions 	assert(fUserNotifications->getNextIndexOfObject(notification, 0) == -1);
46*4d495c6eSApple OSS Distributions 	fUserNotifications->setObject(notification);
47*4d495c6eSApple OSS Distributions 	IOLockUnlock(fLock);
48*4d495c6eSApple OSS Distributions }
49*4d495c6eSApple OSS Distributions 
50*4d495c6eSApple OSS Distributions void
trimUserNotificationsLocked()51*4d495c6eSApple OSS Distributions TestIOServiceUserNotification::trimUserNotificationsLocked()
52*4d495c6eSApple OSS Distributions {
53*4d495c6eSApple OSS Distributions 	OSArray * remaining = OSArray::withCapacity(1);
54*4d495c6eSApple OSS Distributions 	if (!remaining) {
55*4d495c6eSApple OSS Distributions 		return;
56*4d495c6eSApple OSS Distributions 	}
57*4d495c6eSApple OSS Distributions 	fUserNotifications->iterateObjects(^(OSObject * obj) {
58*4d495c6eSApple OSS Distributions 		if (obj->getRetainCount() != 1) {
59*4d495c6eSApple OSS Distributions 		        remaining->setObject(obj);
60*4d495c6eSApple OSS Distributions 		}
61*4d495c6eSApple OSS Distributions 		return false;
62*4d495c6eSApple OSS Distributions 	});
63*4d495c6eSApple OSS Distributions 	fUserNotifications->release();
64*4d495c6eSApple OSS Distributions 	fUserNotifications = remaining;
65*4d495c6eSApple OSS Distributions }
66*4d495c6eSApple OSS Distributions 
67*4d495c6eSApple OSS Distributions size_t
getUserNotificationLeakCount()68*4d495c6eSApple OSS Distributions TestIOServiceUserNotification::getUserNotificationLeakCount()
69*4d495c6eSApple OSS Distributions {
70*4d495c6eSApple OSS Distributions 	size_t count = 0;
71*4d495c6eSApple OSS Distributions 	IOLockLock(fLock);
72*4d495c6eSApple OSS Distributions 	trimUserNotificationsLocked();
73*4d495c6eSApple OSS Distributions 	count = fUserNotifications->getCount();
74*4d495c6eSApple OSS Distributions 	IOLockUnlock(fLock);
75*4d495c6eSApple OSS Distributions 	return count;
76*4d495c6eSApple OSS Distributions }
77*4d495c6eSApple OSS Distributions 
78*4d495c6eSApple OSS Distributions bool
start(IOService * provider)79*4d495c6eSApple OSS Distributions TestIOServiceUserNotificationUserClient::start(IOService * provider)
80*4d495c6eSApple OSS Distributions {
81*4d495c6eSApple OSS Distributions 	if (!IOUserClient::start(provider)) {
82*4d495c6eSApple OSS Distributions 		return false;
83*4d495c6eSApple OSS Distributions 	}
84*4d495c6eSApple OSS Distributions 	fProvider = OSDynamicCast(TestIOServiceUserNotification, provider);
85*4d495c6eSApple OSS Distributions 	assert(fProvider);
86*4d495c6eSApple OSS Distributions 	return true;
87*4d495c6eSApple OSS Distributions }
88*4d495c6eSApple OSS Distributions 
89*4d495c6eSApple OSS Distributions IONotifier *
registerInterest(const OSSymbol * typeOfInterest,IOServiceInterestHandler handler,void * target,void * ref)90*4d495c6eSApple OSS Distributions TestIOServiceUserNotificationUserClient::registerInterest(const OSSymbol * typeOfInterest,
91*4d495c6eSApple OSS Distributions     IOServiceInterestHandler handler,
92*4d495c6eSApple OSS Distributions     void * target,
93*4d495c6eSApple OSS Distributions     void * ref)
94*4d495c6eSApple OSS Distributions {
95*4d495c6eSApple OSS Distributions 	IONotifier * notify = IOService::registerInterest(typeOfInterest, handler, target, ref);
96*4d495c6eSApple OSS Distributions 
97*4d495c6eSApple OSS Distributions 	// No straightforward way to make sure registerInterest is called from the test app
98*4d495c6eSApple OSS Distributions 	// Could check if handler is _ZN32IOServiceMessageUserNotification8_handlerEPvS0_jP9IOServiceS0_m
99*4d495c6eSApple OSS Distributions 	// But still cannot rule out other user process regisering interest
100*4d495c6eSApple OSS Distributions 	OSObject * obj = (OSObject *)target;
101*4d495c6eSApple OSS Distributions 	// Just panic the system if target isn't OSObject
102*4d495c6eSApple OSS Distributions 	fProvider->registerUserNotification(obj);
103*4d495c6eSApple OSS Distributions 
104*4d495c6eSApple OSS Distributions 	return notify;
105*4d495c6eSApple OSS Distributions }
106*4d495c6eSApple OSS Distributions 
107*4d495c6eSApple OSS Distributions IOReturn
clientClose()108*4d495c6eSApple OSS Distributions TestIOServiceUserNotificationUserClient::clientClose()
109*4d495c6eSApple OSS Distributions {
110*4d495c6eSApple OSS Distributions 	if (!isInactive()) {
111*4d495c6eSApple OSS Distributions 		terminate();
112*4d495c6eSApple OSS Distributions 	}
113*4d495c6eSApple OSS Distributions 	return kIOReturnSuccess;
114*4d495c6eSApple OSS Distributions }
115*4d495c6eSApple OSS Distributions 
116*4d495c6eSApple OSS Distributions IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)117*4d495c6eSApple OSS Distributions TestIOServiceUserNotificationUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
118*4d495c6eSApple OSS Distributions     IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
119*4d495c6eSApple OSS Distributions {
120*4d495c6eSApple OSS Distributions 	if (selector == 0) {
121*4d495c6eSApple OSS Distributions 		registerService();
122*4d495c6eSApple OSS Distributions 	} else if (selector == 1 && args->scalarOutputCount >= 1) {
123*4d495c6eSApple OSS Distributions 		args->scalarOutput[0] = fProvider->getUserNotificationLeakCount();
124*4d495c6eSApple OSS Distributions 	}
125*4d495c6eSApple OSS Distributions 	return kIOReturnSuccess;
126*4d495c6eSApple OSS Distributions }
127*4d495c6eSApple OSS Distributions 
128*4d495c6eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
129