1/*-
2 * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: src/sys/sys/eventhandler.h,v 1.33.2.1 2006/05/16 07:27:49 ps Exp $
27 */
28#ifndef SYS_EVENTHANDLER_H
29#define SYS_EVENTHANDLER_H
30
31#include <sys/lock.h>
32#include <sys/ktr.h>
33#include <sys/mutex.h>
34#include <sys/queue.h>
35
36struct eventhandler_entry {
37	TAILQ_ENTRY(eventhandler_entry)	ee_link;
38	int				ee_priority;
39#define	EHE_DEAD_PRIORITY	(-1)
40	void				*ee_arg;
41};
42
43struct eventhandler_list {
44	char				*el_name;
45	int				el_flags;
46#define EHL_INITTED	(1<<0)
47	u_int				el_runcount;
48	struct mtx			el_lock;
49	TAILQ_ENTRY(eventhandler_list)	el_link;
50	TAILQ_HEAD(,eventhandler_entry)	el_entries;
51};
52
53typedef struct eventhandler_entry	*eventhandler_tag;
54
55#define	EHL_LOCK(p)		mtx_lock(&(p)->el_lock)
56#define	EHL_UNLOCK(p)		mtx_unlock(&(p)->el_lock)
57#define	EHL_LOCK_ASSERT(p, x)	mtx_assert(&(p)->el_lock, x)
58
59/*
60 * Macro to invoke the handlers for a given event.
61 */
62#define _EVENTHANDLER_INVOKE(name, list, ...) do {			\
63	struct eventhandler_entry *_ep;					\
64	struct eventhandler_entry_ ## name *_t;				\
65									\
66	KASSERT((list)->el_flags & EHL_INITTED,				\
67 	   ("eventhandler_invoke: running non-inited list"));		\
68	EHL_LOCK_ASSERT((list), MA_OWNED);				\
69	(list)->el_runcount++;						\
70	KASSERT((list)->el_runcount > 0,				\
71	    ("eventhandler_invoke: runcount overflow"));		\
72	CTR0(KTR_EVH, "eventhandler_invoke(\"" __STRING(name) "\")");	\
73	TAILQ_FOREACH(_ep, &((list)->el_entries), ee_link) {		\
74		if (_ep->ee_priority != EHE_DEAD_PRIORITY) {		\
75			EHL_UNLOCK((list));				\
76			_t = (struct eventhandler_entry_ ## name *)_ep;	\
77			CTR1(KTR_EVH, "eventhandler_invoke: executing %p", \
78 			    (void *)_t->eh_func);			\
79			_t->eh_func(_ep->ee_arg , ## __VA_ARGS__);	\
80			EHL_LOCK((list));				\
81		}							\
82	}								\
83	KASSERT((list)->el_runcount > 0,				\
84	    ("eventhandler_invoke: runcount underflow"));		\
85	(list)->el_runcount--;						\
86	if ((list)->el_runcount == 0)					\
87		eventhandler_prune_list(list);				\
88	EHL_UNLOCK((list));						\
89} while (0)
90
91/*
92 * Slow handlers are entirely dynamic; lists are created
93 * when entries are added to them, and thus have no concept of "owner",
94 *
95 * Slow handlers need to be declared, but do not need to be defined. The
96 * declaration must be in scope wherever the handler is to be invoked.
97 */
98#define EVENTHANDLER_DECLARE(name, type)				\
99struct eventhandler_entry_ ## name 					\
100{									\
101	struct eventhandler_entry	ee;				\
102	type				eh_func;			\
103};									\
104struct __hack
105
106#define EVENTHANDLER_INVOKE(name, ...)					\
107do {									\
108	struct eventhandler_list *_el;					\
109									\
110	if ((_el = eventhandler_find_list(#name)) != NULL) 		\
111		_EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__);	\
112} while (0)
113
114#define EVENTHANDLER_REGISTER(name, func, arg, priority)		\
115	eventhandler_register(NULL, #name, func, arg, priority)
116
117#define EVENTHANDLER_DEREGISTER(name, tag) 				\
118do {									\
119	struct eventhandler_list *_el;					\
120									\
121	if ((_el = eventhandler_find_list(#name)) != NULL)		\
122		eventhandler_deregister(_el, tag);			\
123} while(0)
124
125
126eventhandler_tag eventhandler_register(struct eventhandler_list *list,
127	    const char *name, void *func, void *arg, int priority);
128void	eventhandler_deregister(struct eventhandler_list *list,
129	    eventhandler_tag tag);
130struct eventhandler_list *eventhandler_find_list(const char *name);
131void	eventhandler_prune_list(struct eventhandler_list *list);
132
133/*
134 * Standard system event queues.
135 */
136
137/* Generic priority levels */
138#define	EVENTHANDLER_PRI_FIRST	0
139#define	EVENTHANDLER_PRI_ANY	10000
140#define	EVENTHANDLER_PRI_LAST	20000
141
142/* Shutdown events */
143typedef void (*shutdown_fn)(void *, int);
144
145#define	SHUTDOWN_PRI_FIRST	EVENTHANDLER_PRI_FIRST
146#define	SHUTDOWN_PRI_DEFAULT	EVENTHANDLER_PRI_ANY
147#define	SHUTDOWN_PRI_LAST	EVENTHANDLER_PRI_LAST
148
149EVENTHANDLER_DECLARE(shutdown_pre_sync, shutdown_fn);	/* before fs sync */
150EVENTHANDLER_DECLARE(shutdown_post_sync, shutdown_fn);	/* after fs sync */
151EVENTHANDLER_DECLARE(shutdown_final, shutdown_fn);
152
153/* Low memory event */
154typedef void (*vm_lowmem_handler_t)(void *, int);
155#define	LOWMEM_PRI_DEFAULT	EVENTHANDLER_PRI_FIRST
156EVENTHANDLER_DECLARE(vm_lowmem, vm_lowmem_handler_t);
157
158/*
159 * Process events
160 * process_fork and exit handlers are called without Giant.
161 * exec handlers are called with Giant, but that is by accident.
162 */
163struct proc;
164
165typedef void (*exitlist_fn)(void *, struct proc *);
166typedef void (*forklist_fn)(void *, struct proc *, struct proc *, int);
167typedef void (*execlist_fn)(void *, struct proc *);
168
169EVENTHANDLER_DECLARE(process_exit, exitlist_fn);
170EVENTHANDLER_DECLARE(process_fork, forklist_fn);
171EVENTHANDLER_DECLARE(process_exec, execlist_fn);
172
173typedef void (*uma_zone_chfn)(void *);
174EVENTHANDLER_DECLARE(nmbclusters_change, uma_zone_chfn);
175EVENTHANDLER_DECLARE(maxsockets_change, uma_zone_chfn);
176#endif /* SYS_EVENTHANDLER_H */
177