]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/subr_eventhandler.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / subr_eventhandler.c
index 65c5975e330bf49ca04467126ec8392730ec9a0b..167a99befcad90bf7dc874205a63eda73f8c6522 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2016-2019 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 
 int evh_debug = 0;
 
-MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records");
-
 SYSCTL_NODE(_kern, OID_AUTO, eventhandler, CTLFLAG_RW | CTLFLAG_LOCKED,
     0, "Eventhandler");
 SYSCTL_INT(_kern_eventhandler, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_LOCKED,
     &evh_debug, 0, "Eventhandler debug mode");
 
-struct eventhandler_entry_arg eventhandler_entry_dummy_arg = {{0}};
+struct eventhandler_entry_arg eventhandler_entry_dummy_arg = { .ee_fm_uuid = { 0 }, .ee_fr_uuid = { 0 } };
 
 /* List of 'slow' lists */
 static struct eventhandler_lists_ctxt evthdlr_lists_ctxt_glb;
-static lck_grp_attr_t   *eventhandler_mutex_grp_attr;
-static lck_grp_t        *eventhandler_mutex_grp;
-static lck_attr_t       *eventhandler_mutex_attr;
+static LCK_GRP_DECLARE(eventhandler_mutex_grp, "eventhandler");
 
-static lck_grp_attr_t   *el_lock_grp_attr;
-lck_grp_t        *el_lock_grp;
-lck_attr_t       *el_lock_attr;
+static unsigned int eg_size;    /* size of eventhandler_entry_generic */
+static struct mcache *eg_cache; /* mcache for eventhandler_entry_generic */
 
-struct eventhandler_entry_generic
-{
-       struct eventhandler_entry       ee;
-       void                    (* func)(void);
+static unsigned int el_size;    /* size of eventhandler_list */
+static struct mcache *el_cache; /* mcache for eventhandler_list */
+
+LCK_GRP_DECLARE(el_lock_grp, "eventhandler list");
+LCK_ATTR_DECLARE(el_lock_attr, 0, 0);
+
+struct eventhandler_entry_generic {
+       struct eventhandler_entry       ee;
+       void                           *func;
 };
 
 static struct eventhandler_list *_eventhandler_find_list(
-    struct eventhandler_lists_ctxt *evthdlr_lists_ctxt, const char *name);
+       struct eventhandler_lists_ctxt *evthdlr_lists_ctxt, const char *name);
 
 void
 eventhandler_lists_ctxt_init(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt)
@@ -101,7 +101,7 @@ eventhandler_lists_ctxt_init(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt)
        TAILQ_INIT(&evthdlr_lists_ctxt->eventhandler_lists);
        evthdlr_lists_ctxt->eventhandler_lists_initted = 1;
        lck_mtx_init(&evthdlr_lists_ctxt->eventhandler_mutex,
-           eventhandler_mutex_grp, eventhandler_mutex_attr);
+           &eventhandler_mutex_grp, LCK_ATTR_NULL);
 }
 
 /*
@@ -110,17 +110,22 @@ eventhandler_lists_ctxt_init(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt)
 void
 eventhandler_init(void)
 {
-       eventhandler_mutex_grp_attr = lck_grp_attr_alloc_init();
-       eventhandler_mutex_grp = lck_grp_alloc_init("eventhandler",
-           eventhandler_mutex_grp_attr);
-       eventhandler_mutex_attr = lck_attr_alloc_init();
+       eventhandler_lists_ctxt_init(&evthdlr_lists_ctxt_glb);
 
-       el_lock_grp_attr = lck_grp_attr_alloc_init();
-       el_lock_grp = lck_grp_alloc_init("eventhandler list",
-           el_lock_grp_attr);
-       el_lock_attr = lck_attr_alloc_init();
+       eg_size = sizeof(struct eventhandler_entry_generic);
+       eg_cache = mcache_create("eventhdlr_generic", eg_size,
+           sizeof(uint64_t), 0, MCR_SLEEP);
 
-       eventhandler_lists_ctxt_init(&evthdlr_lists_ctxt_glb);
+       el_size = sizeof(struct eventhandler_list);
+       el_cache = mcache_create("eventhdlr_list", el_size,
+           sizeof(uint64_t), 0, MCR_SLEEP);
+}
+
+void
+eventhandler_reap_caches(boolean_t purge)
+{
+       mcache_reap_now(eg_cache, purge);
+       mcache_reap_now(el_cache, purge);
 }
 
 /*
@@ -129,21 +134,24 @@ eventhandler_init(void)
  */
 static eventhandler_tag
 eventhandler_register_internal(
-    struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
-    struct eventhandler_list *list,
-    const char *name, eventhandler_tag epn)
+       struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
+       struct eventhandler_list *list,
+       const char *name, eventhandler_tag epn)
 {
-       struct eventhandler_list                *new_list;
-       struct eventhandler_entry               *ep;
+       struct eventhandler_list                *new_list;
+       struct eventhandler_entry               *ep;
 
-       if (evthdlr_lists_ctxt == NULL)
+       VERIFY(strlen(name) <= (sizeof(new_list->el_name) - 1));
+
+       if (evthdlr_lists_ctxt == NULL) {
                evthdlr_lists_ctxt = &evthdlr_lists_ctxt_glb;
+       }
 
        VERIFY(evthdlr_lists_ctxt->eventhandler_lists_initted); /* eventhandler registered too early */
        VERIFY(epn != NULL); /* cannot register NULL event */
 
        /* lock the eventhandler lists */
-       lck_mtx_lock(&evthdlr_lists_ctxt->eventhandler_mutex);
+       lck_mtx_lock_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
 
        /* Do we need to find/create the (slow) list? */
        if (list == NULL) {
@@ -152,27 +160,21 @@ eventhandler_register_internal(
 
                /* Do we need to create the list? */
                if (list == NULL) {
-                       lck_mtx_unlock(&evthdlr_lists_ctxt->eventhandler_mutex);
-
-                       MALLOC(new_list, struct eventhandler_list *,
-                           sizeof(struct eventhandler_list) + strlen(name) + 1,
-                           M_EVENTHANDLER, M_WAITOK);
-
-                       /* If someone else created it already, then use that one. */
-                       lck_mtx_lock(&evthdlr_lists_ctxt->eventhandler_mutex);
-                       list = _eventhandler_find_list(evthdlr_lists_ctxt, name);
-                       if (list != NULL) {
-                               FREE(new_list, M_EVENTHANDLER);
-                       } else {
-                               evhlog((LOG_DEBUG, "%s: creating list \"%s\"", __func__, name));
-                               list = new_list;
-                               list->el_flags = 0;
-                               list->el_runcount = 0;
-                               bzero(&list->el_lock, sizeof(list->el_lock));
-                               list->el_name = (char *)list + sizeof(struct eventhandler_list);
-                               strlcpy(list->el_name, name, strlen(name) + 1);
-                               TAILQ_INSERT_HEAD(&evthdlr_lists_ctxt->eventhandler_lists, list, el_link);
+                       lck_mtx_convert_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
+                       new_list = mcache_alloc(el_cache, MCR_SLEEP);
+                       if (new_list == NULL) {
+                               evhlog((LOG_DEBUG, "%s: Can't allocate list \"%s\"", __func__, name));
+                               lck_mtx_unlock(&evthdlr_lists_ctxt->eventhandler_mutex);
+                               return NULL;
                        }
+                       bzero(new_list, el_size);
+                       evhlog((LOG_DEBUG, "%s: creating list \"%s\"", __func__, name));
+                       list = new_list;
+                       list->el_flags = 0;
+                       list->el_runcount = 0;
+                       bzero(&list->el_lock, sizeof(list->el_lock));
+                       (void) snprintf(list->el_name, sizeof(list->el_name), "%s", name);
+                       TAILQ_INSERT_HEAD(&evthdlr_lists_ctxt->eventhandler_lists, list, el_link);
                }
        }
        if (!(list->el_flags & EHL_INITTED)) {
@@ -186,8 +188,8 @@ eventhandler_register_internal(
            ("%s: handler for %s registered with dead priority", __func__, name));
 
        /* sort it into the list */
-       evhlog((LOG_DEBUG, "%s: adding item %p (function %p to \"%s\"", __func__, VM_KERNEL_ADDRPERM(epn),
-           VM_KERNEL_UNSLIDE(((struct eventhandler_entry_generic *)epn)->func), name));
+       evhlog((LOG_DEBUG, "%s: adding item %p (function %p to \"%s\"", __func__, (void *)VM_KERNEL_ADDRPERM(epn),
+           (void *)VM_KERNEL_UNSLIDE(((struct eventhandler_entry_generic *)epn)->func), name));
        EHL_LOCK(list);
        TAILQ_FOREACH(ep, &list->el_entries, ee_link) {
                if (ep->ee_priority != EHE_DEAD_PRIORITY &&
@@ -196,10 +198,11 @@ eventhandler_register_internal(
                        break;
                }
        }
-       if (ep == NULL)
+       if (ep == NULL) {
                TAILQ_INSERT_TAIL(&list->el_entries, epn, ee_link);
+       }
        EHL_UNLOCK(list);
-       return(epn);
+       return epn;
 }
 
 eventhandler_tag
@@ -207,42 +210,47 @@ eventhandler_register(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
     struct eventhandler_list *list, const char *name,
     void *func, struct eventhandler_entry_arg arg, int priority)
 {
-       struct eventhandler_entry_generic       *eg;
+       struct eventhandler_entry_generic       *eg;
 
        /* allocate an entry for this handler, populate it */
-       MALLOC(eg, struct eventhandler_entry_generic *,
-           sizeof(struct eventhandler_entry_generic),
-           M_EVENTHANDLER, M_WAITOK | M_ZERO);
-
+       eg = mcache_alloc(eg_cache, MCR_SLEEP);
+       if (eg == NULL) {
+               evhlog((LOG_DEBUG, "%s: Can't allocate entry to register for event list "
+                   "\"%s\"", __func__, name));
+               return NULL;
+       }
+       bzero(eg, eg_size);
        eg->func = func;
        eg->ee.ee_arg = arg;
        eg->ee.ee_priority = priority;
 
-       return (eventhandler_register_internal(evthdlr_lists_ctxt, list, name, &eg->ee));
+       return eventhandler_register_internal(evthdlr_lists_ctxt, list, name, &eg->ee);
 }
 
 void
 eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
 {
-       struct eventhandler_entry       *ep = tag;
+       struct eventhandler_entry       *ep = tag;
 
        EHL_LOCK_ASSERT(list, LCK_MTX_ASSERT_OWNED);
        if (ep != NULL) {
                /* remove just this entry */
                if (list->el_runcount == 0) {
-                       evhlog((LOG_DEBUG, "%s: removing item %p from \"%s\"", __func__, VM_KERNEL_ADDRPERM(ep),
+                       evhlog((LOG_DEBUG, "%s: removing item %p from \"%s\"", __func__, (void *)VM_KERNEL_ADDRPERM(ep),
                            list->el_name));
                        /*
                         * We may have purged the list because of certain events.
                         * Make sure that is not the case when a specific entry
                         * is being removed.
                         */
-                       if (!TAILQ_EMPTY(&list->el_entries))
+                       if (!TAILQ_EMPTY(&list->el_entries)) {
                                TAILQ_REMOVE(&list->el_entries, ep, ee_link);
-                       FREE(ep, M_EVENTHANDLER);
+                       }
+                       EHL_LOCK_CONVERT(list);
+                       mcache_free(eg_cache, ep);
                } else {
                        evhlog((LOG_DEBUG, "%s: marking item %p from \"%s\" as dead", __func__,
-                           VM_KERNEL_ADDRPERM(ep), list->el_name));
+                           (void *)VM_KERNEL_ADDRPERM(ep), list->el_name));
                        ep->ee_priority = EHE_DEAD_PRIORITY;
                }
        } else {
@@ -250,20 +258,22 @@ eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag)
                if (list->el_runcount == 0) {
                        evhlog((LOG_DEBUG, "%s: removing all items from \"%s\"", __func__,
                            list->el_name));
+                       EHL_LOCK_CONVERT(list);
                        while (!TAILQ_EMPTY(&list->el_entries)) {
                                ep = TAILQ_FIRST(&list->el_entries);
                                TAILQ_REMOVE(&list->el_entries, ep, ee_link);
-                               FREE(ep, M_EVENTHANDLER);
+                               mcache_free(eg_cache, ep);
                        }
                } else {
                        evhlog((LOG_DEBUG, "%s: marking all items from \"%s\" as dead",
                            __func__, list->el_name));
                        TAILQ_FOREACH(ep, &list->el_entries, ee_link)
-                               ep->ee_priority = EHE_DEAD_PRIORITY;
+                       ep->ee_priority = EHE_DEAD_PRIORITY;
                }
        }
-       while (list->el_runcount > 0)
-               msleep((caddr_t)list, &list->el_lock, 0, "evhrm", 0);
+       while (list->el_runcount > 0) {
+               msleep((caddr_t)list, &list->el_lock, PSPIN, "evhrm", 0);
+       }
        EHL_UNLOCK(list);
 }
 
@@ -274,16 +284,17 @@ static struct eventhandler_list *
 _eventhandler_find_list(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
     const char *name)
 {
-       struct eventhandler_list        *list;
+       struct eventhandler_list        *list;
 
        VERIFY(evthdlr_lists_ctxt != NULL);
 
        LCK_MTX_ASSERT(&evthdlr_lists_ctxt->eventhandler_mutex, LCK_MTX_ASSERT_OWNED);
        TAILQ_FOREACH(list, &evthdlr_lists_ctxt->eventhandler_lists, el_link) {
-               if (!strcmp(name, list->el_name))
+               if (!strcmp(name, list->el_name)) {
                        break;
+               }
        }
-       return (list);
+       return list;
 }
 
 /*
@@ -293,22 +304,26 @@ struct eventhandler_list *
 eventhandler_find_list(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt,
     const char *name)
 {
-       struct eventhandler_list        *list;
+       struct eventhandler_list        *list;
 
-       if (evthdlr_lists_ctxt == NULL)
+       if (evthdlr_lists_ctxt == NULL) {
                evthdlr_lists_ctxt = &evthdlr_lists_ctxt_glb;
+       }
 
-       if (!evthdlr_lists_ctxt->eventhandler_lists_initted)
-               return(NULL);
+       if (!evthdlr_lists_ctxt->eventhandler_lists_initted) {
+               return NULL;
+       }
 
        /* scan looking for the requested list */
-       lck_mtx_lock(&evthdlr_lists_ctxt->eventhandler_mutex);
+       lck_mtx_lock_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
        list = _eventhandler_find_list(evthdlr_lists_ctxt, name);
-       if (list != NULL)
-               EHL_LOCK(list);
+       if (list != NULL) {
+               lck_mtx_convert_spin(&evthdlr_lists_ctxt->eventhandler_mutex);
+               EHL_LOCK_SPIN(list);
+       }
        lck_mtx_unlock(&evthdlr_lists_ctxt->eventhandler_mutex);
 
-       return(list);
+       return list;
 }
 
 /*
@@ -325,12 +340,13 @@ eventhandler_prune_list(struct eventhandler_list *list)
        TAILQ_FOREACH_SAFE(ep, &list->el_entries, ee_link, en) {
                if (ep->ee_priority == EHE_DEAD_PRIORITY) {
                        TAILQ_REMOVE(&list->el_entries, ep, ee_link);
-                       FREE(ep, M_EVENTHANDLER);
+                       mcache_free(eg_cache, ep);
                        pruned++;
                }
        }
-       if (pruned > 0)
+       if (pruned > 0) {
                wakeup(list);
+       }
 }
 
 /*
@@ -343,17 +359,17 @@ void
 eventhandler_lists_ctxt_destroy(struct eventhandler_lists_ctxt *evthdlr_lists_ctxt)
 {
        struct eventhandler_list        *list = NULL;
-       struct eventhandler_list        *list_next = NULL;
+       struct eventhandler_list        *list_next = NULL;
 
        lck_mtx_lock(&evthdlr_lists_ctxt->eventhandler_mutex);
        TAILQ_FOREACH_SAFE(list, &evthdlr_lists_ctxt->eventhandler_lists,
            el_link, list_next) {
                VERIFY(TAILQ_EMPTY(&list->el_entries));
                EHL_LOCK_DESTROY(list);
-               FREE(list, M_EVENTHANDLER);
+               mcache_free(el_cache, list);
        }
        lck_mtx_unlock(&evthdlr_lists_ctxt->eventhandler_mutex);
        lck_mtx_destroy(&evthdlr_lists_ctxt->eventhandler_mutex,
-           eventhandler_mutex_grp);
+           &eventhandler_mutex_grp);
        return;
 }