+void
+TestUserClient::stop( IOService *provider)
+{
+ kprintf("TestUserClient::stop\n");
+}
+bool
+TestUserClient::finalize(IOOptionBits options)
+{
+ kprintf("TestUserClient::finalize\n");
+ return true;
+}
+IOReturn
+TestUserClient::externalMethod( uint32_t selector,
+ IOExternalMethodArguments * arguments,
+ IOExternalMethodDispatch * dispatch,
+ OSObject * target,
+ void * reference )
+{
+ getProvider()->terminate();
+ IOSleep(500);
+ return 0;
+}
+OSDefineMetaClassAndStructors(TestUserClient, IOUserClient);
+#endif
+
+static int
+IOServiceTest(int newValue)
+{
+ OSDictionary * matching;
+ IONotifier * note;
+ __block IOService * found;
+
+#if 0
+ found = new IOService;
+ found->init();
+ found->setName("IOTestUserClientProvider");
+ found->attach(IOService::getPlatform());
+ found->setProperty("IOUserClientClass", "TestUserClient");
+ found->registerService();
+#endif
+
+ matching = IOService::serviceMatching("IOPlatformExpert");
+ assert(matching);
+ found = nullptr;
+ note = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0,
+ ^bool (IOService * newService, IONotifier * notifier) {
+ kprintf("found %s, %d\n", newService->getName(), newService->getRetainCount());
+ found = newService;
+ found->retain();
+ return true;
+ }
+ );
+ assert(note);
+ assert(found);
+ matching->release();
+ note->remove();
+
+ note = found->registerInterest(gIOBusyInterest,
+ ^IOReturn (uint32_t messageType, IOService * provider,
+ void * messageArgument, size_t argSize) {
+ kprintf("%p messageType 0x%08x %p\n", provider, messageType, messageArgument);
+ return kIOReturnSuccess;
+ });
+ assert(note);
+ IOSleep(1 * 1000);
+ note->remove();
+ found->release();
+
+ return 0;
+}
+
+static void
+OSStaticPtrCastTests()
+{
+ // const& overload
+ {
+ OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
+ OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
+ assert(collection == dict);
+ }
+ {
+ OSSharedPtr<OSDictionary> const dict = nullptr;
+ OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
+ assert(collection == nullptr);
+ }
+ // && overload
+ {
+ OSSharedPtr<OSDictionary> dict = OSMakeShared<OSDictionary>();
+ OSDictionary* oldDict = dict.get();
+ OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
+ assert(collection.get() == oldDict);
+ assert(dict == nullptr);
+ }
+ {
+ OSSharedPtr<OSDictionary> dict = nullptr;
+ OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
+ assert(collection == nullptr);
+ assert(dict == nullptr);
+ }
+}
+
+static void
+OSConstPtrCastTests()
+{
+ // const& overload
+ {
+ OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
+ OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
+ assert(dict2 == dict);
+ }
+ {
+ OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
+ OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
+ assert(dict2 == dict);
+ }
+ {
+ OSSharedPtr<OSDictionary const> const dict = nullptr;
+ OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
+ assert(dict2 == nullptr);
+ }
+ {
+ OSSharedPtr<OSDictionary const> const dict = nullptr;
+ OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
+ assert(dict2 == nullptr);
+ }
+
+ // && overload
+ {
+ OSSharedPtr<OSDictionary const> dict = OSMakeShared<OSDictionary>();
+ OSDictionary const* oldDict = dict.get();
+ OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
+ assert(dict == nullptr);
+ assert(dict2 == oldDict);
+ }
+ {
+ OSSharedPtr<OSDictionary const> dict = nullptr;
+ OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
+ assert(dict == nullptr);
+ assert(dict2 == nullptr);
+ }
+}
+
+static void
+OSDynamicPtrCastTests()
+{
+ OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
+ {
+ OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
+ assert(collection != nullptr);
+ }
+ {
+ OSSharedPtr<OSArray> array = OSDynamicPtrCast<OSArray>(dict);
+ assert(array == nullptr);
+ assert(dict != nullptr);
+ }
+ {
+ OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
+ OSTaggedSharedPtr<OSCollection, OSCollection> collection = OSDynamicPtrCast<OSCollection>(taggedDict);
+ assert(collection != nullptr);
+ }
+ {
+ OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
+ OSTaggedSharedPtr<OSArray, OSCollection> array = OSDynamicPtrCast<OSArray>(taggedDict);
+ assert(array == nullptr);
+ assert(dict != nullptr);
+ }
+ {
+ OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
+ assert(collection.get() == OSDynamicCast(OSDictionary, dict.get()));
+ OSSharedPtr<OSDictionary> newDict = OSDynamicPtrCast<OSDictionary>(os::move(collection));
+ assert(collection == nullptr);
+ assert(newDict != nullptr);
+ assert(newDict.get() == dict.get());
+ }
+}
+
+static int
+OSSharedPtrTests(int)
+{
+ OSDynamicPtrCastTests();
+ OSConstPtrCastTests();
+ OSStaticPtrCastTests();
+ return 0;
+}
+
+#endif /* DEVELOPMENT || DEBUG */
+
+#ifndef __clang_analyzer__
+// All the scary things that this function is doing, such as the intentional
+// overrelease of an OSData, are hidden from the static analyzer.
+static int
+sysctl_iokittest(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
+{
+ int error;
+ int newValue, changed;
+
+ error = sysctl_io_number(req, 0, sizeof(int), &newValue, &changed);
+ if (error) {
+ return error;
+ }
+
+#if DEVELOPMENT || DEBUG
+ if (changed && (66 == newValue)) {
+ IOReturn ret;
+ IOWorkLoop * wl = IOWorkLoop::workLoop();
+ IOCommandGate * cg = IOCommandGate::commandGate(wl);
+ ret = wl->addEventSource(cg);
+
+ struct x {
+ uint64_t h;
+ uint64_t l;
+ };
+ struct x y;
+
+ y.h = 0x1111111122222222;
+ y.l = 0x3333333344444444;
+
+ kprintf("ret1 %d\n", ret);
+ ret = cg->runActionBlock(^(){
+ printf("hello %d 0x%qx\n", wl->inGate(), y.h);
+ return 99;
+ });
+ kprintf("ret %d\n", ret);
+ }
+
+ if (changed && (999 == newValue)) {
+ OSData * data = OSData::withCapacity(16);
+ data->release();
+ data->release();
+ }
+
+ if (changed && (newValue >= 6666) && (newValue <= 6669)) {
+ OSIterator * iter;
+ IOService * service;
+
+ service = NULL;
+ iter = IOService::getMatchingServices(IOService::nameMatching("XHC1"));
+ if (iter && (service = (IOService *) iter->getNextObject())) {
+ if (newValue == 6666) {
+ IOLog("terminating 0x%qx\n", service->getRegistryEntryID());
+ service->terminate();
+ } else if (newValue == 6667) {
+ IOLog("register 0x%qx\n", service->getRegistryEntryID());
+ service->registerService();
+ }
+ }
+ OSSafeReleaseNULL(iter);
+ if (service) {
+ return 0;
+ }
+ }
+
+
+ if (changed && newValue) {
+ error = IOWorkLoopTest(newValue);
+ assert(KERN_SUCCESS == error);
+ error = IOServiceTest(newValue);
+ assert(KERN_SUCCESS == error);
+ error = OSCollectionTest(newValue);
+ assert(KERN_SUCCESS == error);
+ error = OSAllocationTests(newValue);
+ assert(KERN_SUCCESS == error);
+ error = OSBoundedArrayTests(newValue);
+ assert(KERN_SUCCESS == error);
+ error = OSBoundedArrayRefTests(newValue);
+ assert(KERN_SUCCESS == error);
+ error = OSBoundedPtrTests(newValue);
+ assert(KERN_SUCCESS == error);
+ error = IOMemoryDescriptorTest(newValue);
+ assert(KERN_SUCCESS == error);
+ error = OSSharedPtrTests(newValue);
+ assert(KERN_SUCCESS == error);
+ error = IOSharedDataQueue_44636964(newValue);
+ assert(KERN_SUCCESS == error);
+ }
+#endif /* DEVELOPMENT || DEBUG */