+struct IOUserClientOwner
+{
+ task_t task;
+ queue_chain_t taskLink;
+ IOUserClient * uc;
+ queue_chain_t ucLink;
+};
+
+IOReturn
+IOUserClient::registerOwner(task_t task)
+{
+ IOUserClientOwner * owner;
+ IOReturn ret;
+ bool newOwner;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ newOwner = true;
+ ret = kIOReturnSuccess;
+
+ if (!owners.next) queue_init(&owners);
+ else
+ {
+ queue_iterate(&owners, owner, IOUserClientOwner *, ucLink)
+ {
+ if (task != owner->task) continue;
+ newOwner = false;
+ break;
+ }
+ }
+ if (newOwner)
+ {
+ owner = IONew(IOUserClientOwner, 1);
+ if (!newOwner) ret = kIOReturnNoMemory;
+ else
+ {
+ owner->task = task;
+ owner->uc = this;
+ queue_enter_first(&owners, owner, IOUserClientOwner *, ucLink);
+ queue_enter_first(task_io_user_clients(task), owner, IOUserClientOwner *, taskLink);
+ }
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+
+ return (ret);
+}
+
+void
+IOUserClient::noMoreSenders(void)
+{
+ IOUserClientOwner * owner;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ if (owners.next)
+ {
+ while (!queue_empty(&owners))
+ {
+ owner = (IOUserClientOwner *)(void *) queue_first(&owners);
+ queue_remove(task_io_user_clients(owner->task), owner, IOUserClientOwner *, taskLink);
+ queue_remove(&owners, owner, IOUserClientOwner *, ucLink);
+ IODelete(owner, IOUserClientOwner, 1);
+ }
+ owners.next = owners.prev = NULL;
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+}
+
+extern "C" kern_return_t
+iokit_task_terminate(task_t task)
+{
+ IOUserClientOwner * owner;
+ IOUserClient * dead;
+ IOUserClient * uc;
+ queue_head_t * taskque;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ taskque = task_io_user_clients(task);
+ dead = NULL;
+ while (!queue_empty(taskque))
+ {
+ owner = (IOUserClientOwner *)(void *) queue_first(taskque);
+ uc = owner->uc;
+ queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
+ queue_remove(&uc->owners, owner, IOUserClientOwner *, ucLink);
+ if (queue_empty(&uc->owners))
+ {
+ uc->retain();
+ IOLog("destroying out of band connect for %s\n", uc->getName());
+ // now using the uc queue head as a singly linked queue,
+ // leaving .next as NULL to mark it empty
+ uc->owners.next = NULL;
+ uc->owners.prev = (queue_entry_t) dead;
+ dead = uc;
+ }
+ IODelete(owner, IOUserClientOwner, 1);
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+
+ while (dead)
+ {
+ uc = dead;
+ dead = (IOUserClient *)(void *) dead->owners.prev;
+ uc->owners.prev = NULL;
+ if (uc->sharedInstance || !uc->closed) uc->clientDied();
+ uc->release();
+ }
+
+ return (KERN_SUCCESS);
+}
+