Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 5 Apr 2012 18:24:55 GMT
From:      John Baldwin <jhb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 209119 for review
Message-ID:  <201204051824.q35IOtoC097960@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@209119?ac=10

Change 209119 by jhb@jhb_fiver on 2012/04/05 18:24:07

	WIP to partially bring back fast eventhandlers.  However, in this
	incarnation fast lists are in the set of named events, so the
	same API can be used for registering both fast and slow handlers.
	The result is that switching an eventhandler from slow to fast
	no longer requires changing all the callers.

Affected files ...

.. //depot/projects/smpng/share/man/man9/EVENTHANDLER.9#2 edit
.. //depot/projects/smpng/share/man/man9/Makefile#29 edit
.. //depot/projects/smpng/sys/kern/subr_eventhandler.c#26 edit
.. //depot/projects/smpng/sys/sys/eventhandler.h#36 edit

Differences ...

==== //depot/projects/smpng/share/man/man9/EVENTHANDLER.9#2 (text+ko) ====

@@ -33,6 +33,10 @@
 .In sys/eventhandler.h
 .Fn EVENTHANDLER_DECLARE name type
 .Fn EVENTHANDLER_INVOKE name ...
+.Fn EVENTHANDLER_FAST_DECLARE name type
+.Fn EVENTHANDLER_FAST_DEFINE name type
+.Fn EVENTHANDLER_FAST_INVOKE name ...
+.Fn EVENTHANDLER_DEFINE name func arg priority
 .Ft eventhandler_tag
 .Fn EVENTHANDLER_REGISTER name func arg priority
 .Fn EVENTHANDLER_DEREGISTER name tag

==== //depot/projects/smpng/share/man/man9/Makefile#29 (text+ko) ====

@@ -629,8 +629,12 @@
 	drbr.9 drbr_inuse.9 \
 	drbr.9 drbr_stats_update.9
 MLINKS+=EVENTHANDLER.9 EVENTHANDLER_DECLARE.9 \
+	EVENTHANDLER.9 EVENTHANDLER_DEFINE.9 \
 	EVENTHANDLER.9 EVENTHANDLER_DEREGISTER.9 \
 	EVENTHANDLER.9 eventhandler_deregister.9 \
+	EVENTHANDLER.9 EVENTHANDLER_FAST_DECLARE.9 \
+	EVENTHANDLER.9 EVENTHANDLER_FAST_DEFINE.9 \
+	EVENTHANDLER.9 EVENTHANDLER_FAST_INVOKE.9 \
 	EVENTHANDLER.9 eventhandler_find_list.9 \
 	EVENTHANDLER.9 EVENTHANDLER_INVOKE.9 \
 	EVENTHANDLER.9 eventhandler_prune_list.9 \

==== //depot/projects/smpng/sys/kern/subr_eventhandler.c#26 (text+ko) ====

@@ -64,6 +64,28 @@
 SYSINIT(eventhandlers, SI_SUB_EVENTHANDLER, SI_ORDER_FIRST, eventhandler_init,
     NULL);
 
+/*
+ * Initialize a pre-allocated "fast" eventhandler list.  The list's
+ * name is set in 'el_name', but the list is otherwise uninitialized.
+ */
+void
+eventhandler_fast_list_init(void *arg)
+{
+    struct eventhandler_list *list;
+
+    list = arg;
+    CTR2(KTR_EVH, "%s: initializing list \"%s\"", __func__, list->el_name);
+    TAILQ_INIT(&list->el_entries);
+    mtx_init(&list->el_lock, list->el_name, "eventhandler list", MTX_DEF);
+    atomic_store_rel_int(&list->el_flags, EHL_INITTED);
+
+    mtx_lock(&eventhandler_mutex);
+    if (_eventhandler_find_list(list->el_name) != NULL)
+	    panic("Duplicate fast eventhandler list: %s", list->el_name);
+    TAILQ_INSERT_HEAD(&eventhandler_lists, list, el_link);
+    mtx_unlock(&eventhandler_mutex);
+}
+
 /* 
  * Insertion is O(n) due to the priority scan, but optimises to O(1)
  * if all priorities are identical.
@@ -81,7 +103,7 @@
     /* lock the eventhandler lists */
     mtx_lock(&eventhandler_mutex);
 
-    /* Do we need to find/create the (slow) list? */
+    /* Do we need to find/create the list? */
     if (list == NULL) {
 	/* look for a matching, existing list */
 	list = _eventhandler_find_list(name);
@@ -91,7 +113,7 @@
 	    mtx_unlock(&eventhandler_mutex);
 
 	    new_list = malloc(sizeof(struct eventhandler_list) +
-		strlen(name) + 1, M_EVENTHANDLER, M_WAITOK);
+		strlen(name) + 1, M_EVENTHANDLER, M_WAITOK | M_ZERO);
 
 	    /* If someone else created it already, then use that one. */
 	    mtx_lock(&eventhandler_mutex);
@@ -101,20 +123,15 @@
 	    } else {
 		CTR2(KTR_EVH, "%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);
 		strcpy(list->el_name, name);
+		TAILQ_INIT(&list->el_entries);
+		mtx_init(&list->el_lock, name, "eventhandler list", MTX_DEF);
 		TAILQ_INSERT_HEAD(&eventhandler_lists, list, el_link);
+		atomic_store_rel_int(&list->el_flags, EHL_INITTED);
 	    }
 	}
     }
-    if (!(list->el_flags & EHL_INITTED)) {
-	TAILQ_INIT(&list->el_entries);
-	mtx_init(&list->el_lock, name, "eventhandler list", MTX_DEF);
-	atomic_store_rel_int(&list->el_flags, EHL_INITTED);
-    }
     mtx_unlock(&eventhandler_mutex);
 
     KASSERT(epn->ee_priority != EHE_DEAD_PRIORITY,
@@ -244,8 +261,8 @@
 {
     struct eventhandler_list	*list;
 
-    if (!eventhandler_lists_initted)
-	return(NULL);
+    KASSERT(eventhandler_lists_initted,
+	("eventhandler_find_list called too early"));
     
     /* scan looking for the requested list */
     mtx_lock(&eventhandler_mutex);

==== //depot/projects/smpng/sys/sys/eventhandler.h#36 (text+ko) ====

@@ -98,12 +98,40 @@
 } while (0)
 
 /*
- * Slow handlers are entirely dynamic; lists are created
- * when entries are added to them, and thus have no concept of "owner",
+ * Fast handler lists require the eventhandler list be present
+ * at link time.  They don't allow addition of entries to
+ * unknown eventhandler lists, ie. each list must have an
+ * "owner".
+ *
+ * Fast handler lists must be defined once by the owner
+ * of the eventhandler list, and the declaration must be in
+ * scope at any point the list is manipulated.
+ */
+
+/*
+ * Event handlers provide named lists of hooks to be invoked when a
+ * specific event occurs.  Hooks are added and removed to lists that
+ * are identified by name.
+ *
+ * There are two types of event handler lists.
+ *
+ * Default, or "slow" lists allocate the list storage dynamically when
+ * the first hook is registered for an event.  Invoking a default hook
+ * will always have some overhead as it uses an O(n) lookup to find
+ * the event handler list by name.
+ *
+ * "Fast" lists use statically allocated storage for the event handler
+ * list.  As a result, they can avoid the O(n) lookup and should have
+ * very minimal overhead when no hooks are active.  Fast lists can
+ * never be freed, so they cannot be used in kernel modules that
+ * support unloading.  They must also be defined in addition to being
+ * declared.
  *
- * Slow handlers need to be declared, but do not need to be defined. The
- * declaration must be in scope wherever the handler is to be invoked.
+ * Registering a hook for an event or invoking an event requires that
+ * the declaration of the list is in scope.
  */
+
+/* "Slow" list operations. */
 #define EVENTHANDLER_DECLARE(name, type)				\
 struct eventhandler_entry_ ## name 					\
 {									\
@@ -112,6 +140,36 @@
 };									\
 struct __hack
 
+#define EVENTHANDLER_INVOKE(name, ...)					\
+do {									\
+	struct eventhandler_list *_el;					\
+									\
+	if ((_el = eventhandler_find_list(#name)) != NULL) 		\
+		_EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__);	\
+} while (0)
+
+/* "Fast" list operations. */
+#define EVENTHANDLER_FAST_DECLARE(name, type)				\
+extern struct eventhandler_list Xeventhandler_list_ ## name;		\
+EVENTHANDLER_DECLARE(name, type)
+
+#define EVENTHANDLER_FAST_DEFINE(name, type)				\
+struct eventhandler_list Xeventhandler_list_ ## name = { #name };	\
+SYSINIT(eventhandler_list_ ##name, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, \
+    eventhandler_fast_list_init, &Xeventhandler_list_ ## name)
+
+#define EVENTHANDLER_FAST_INVOKE(name, ...) do {			\
+	struct eventhandler_list *_el = &Xeventhandler_list_ ## name ;	\
+									\
+	KASSERT(_el->el_flags & EHL_INITTED,				\
+ 	   ("eventhandler_fast_invoke: too early"));			\
+	if (!TAILQ_EMPTY(&_el->el_entries) {				\
+		EHL_LOCK(_el);						\
+		_EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__);	\
+	}								\
+} while (0)
+
+/* Operations to add and remove hooks. */
 #define EVENTHANDLER_DEFINE(name, func, arg, priority)			\
 	static eventhandler_tag name ## _tag;				\
 	static void name ## _evh_init(void *ctx)			\
@@ -123,15 +181,7 @@
 	    name ## _evh_init, arg);					\
 	struct __hack
 
-#define EVENTHANDLER_INVOKE(name, ...)					\
-do {									\
-	struct eventhandler_list *_el;					\
-									\
-	if ((_el = eventhandler_find_list(#name)) != NULL) 		\
-		_EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__);	\
-} while (0)
-
-#define EVENTHANDLER_REGISTER(name, func, arg, priority)		\
+#define EVENTHANDLER_REGISTER(name, func, arg, priority)	\
 	eventhandler_register(NULL, #name, func, arg, priority)
 
 #define EVENTHANDLER_DEREGISTER(name, tag) 				\
@@ -141,12 +191,12 @@
 	if ((_el = eventhandler_find_list(#name)) != NULL)		\
 		eventhandler_deregister(_el, tag);			\
 } while(0)
-	
 
-eventhandler_tag eventhandler_register(struct eventhandler_list *list, 
+eventhandler_tag eventhandler_register(struct eventhandler_list *list,
 	    const char *name, void *func, void *arg, int priority);
 void	eventhandler_deregister(struct eventhandler_list *list,
 	    eventhandler_tag tag);
+void	eventhandler_fast_list_init(void *arg);
 struct eventhandler_list *eventhandler_find_list(const char *name);
 void	eventhandler_prune_list(struct eventhandler_list *list);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204051824.q35IOtoC097960>