+ reserved = IONew(ExpansionData, 1);
+ if (!reserved) {
+ return false;
+ }
+ }
+ setTerminateDefer(NULL, true);
+ IOStatisticsRegisterCounter();
+
+ return true;
+}
+
+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 (!owner) {
+ 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);
+ if (messageAppSuspended) {
+ task_set_message_app_suspended(task, true);
+ }
+ }
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+
+ return ret;
+}
+
+void
+IOUserClient::noMoreSenders(void)
+{
+ IOUserClientOwner * owner;
+ IOUserClientOwner * iter;
+ queue_head_t * taskque;
+ bool hasMessageAppSuspended;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ if (owners.next) {
+ while (!queue_empty(&owners)) {
+ owner = (IOUserClientOwner *)(void *) queue_first(&owners);
+ taskque = task_io_user_clients(owner->task);
+ queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
+ hasMessageAppSuspended = false;
+ queue_iterate(taskque, iter, IOUserClientOwner *, taskLink) {
+ hasMessageAppSuspended = iter->uc->messageAppSuspended;
+ if (hasMessageAppSuspended) {
+ break;
+ }
+ }
+ task_set_message_app_suspended(owner->task, hasMessageAppSuspended);
+ queue_remove(&owners, owner, IOUserClientOwner *, ucLink);
+ IODelete(owner, IOUserClientOwner, 1);
+ }
+ owners.next = owners.prev = NULL;
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+}
+
+
+extern "C" void
+iokit_task_app_suspended_changed(task_t task)
+{
+ queue_head_t * taskque;
+ IOUserClientOwner * owner;
+ OSSet * set;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ taskque = task_io_user_clients(task);
+ set = NULL;
+ queue_iterate(taskque, owner, IOUserClientOwner *, taskLink) {
+ if (!owner->uc->messageAppSuspended) {
+ continue;
+ }
+ if (!set) {
+ set = OSSet::withCapacity(4);
+ if (!set) {
+ break;
+ }
+ }
+ set->setObject(owner->uc);
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+
+ if (set) {
+ set->iterateObjects(^bool (OSObject * obj) {
+ IOUserClient * uc;
+
+ uc = (typeof(uc))obj;
+#if 0
+ {
+ OSString * str;
+ str = IOCopyLogNameForPID(task_pid(task));
+ IOLog("iokit_task_app_suspended_changed(%s) %s %d\n", str ? str->getCStringNoCopy() : "",
+ uc->getName(), task_is_app_suspended(task));
+ OSSafeReleaseNULL(str);
+ }
+#endif
+ uc->message(kIOMessageTaskAppSuspendedChange, NULL);
+
+ return false;
+ });
+ set->release();
+ }
+}
+
+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();