1a9643ea8Slogwang /*- 2*22ce4affSfengbojiang * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*22ce4affSfengbojiang * 4a9643ea8Slogwang * Copyright (c) 1999 Michael Smith <[email protected]> 5a9643ea8Slogwang * All rights reserved. 6a9643ea8Slogwang * 7a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without 8a9643ea8Slogwang * modification, are permitted provided that the following conditions 9a9643ea8Slogwang * are met: 10a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright 11a9643ea8Slogwang * notice, this list of conditions and the following disclaimer. 12a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright 13a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in the 14a9643ea8Slogwang * documentation and/or other materials provided with the distribution. 15a9643ea8Slogwang * 16a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18a9643ea8Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19a9643ea8Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20a9643ea8Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21a9643ea8Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22a9643ea8Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23a9643ea8Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24a9643ea8Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25a9643ea8Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26a9643ea8Slogwang * SUCH DAMAGE. 27a9643ea8Slogwang * 28a9643ea8Slogwang * $FreeBSD$ 29a9643ea8Slogwang */ 30a9643ea8Slogwang 31a9643ea8Slogwang #ifndef _SYS_EVENTHANDLER_H_ 32a9643ea8Slogwang #define _SYS_EVENTHANDLER_H_ 33a9643ea8Slogwang 34*22ce4affSfengbojiang #include <sys/_eventhandler.h> 35a9643ea8Slogwang #include <sys/lock.h> 36a9643ea8Slogwang #include <sys/ktr.h> 37a9643ea8Slogwang #include <sys/mutex.h> 38a9643ea8Slogwang #include <sys/queue.h> 39a9643ea8Slogwang 40a9643ea8Slogwang #ifdef VIMAGE 41a9643ea8Slogwang struct eventhandler_entry_vimage { 42a9643ea8Slogwang void (* func)(void); /* Original function registered. */ 43a9643ea8Slogwang void *ee_arg; /* Original argument registered. */ 44a9643ea8Slogwang void *sparep[2]; 45a9643ea8Slogwang }; 46a9643ea8Slogwang #endif 47a9643ea8Slogwang 48a9643ea8Slogwang struct eventhandler_list { 49a9643ea8Slogwang char *el_name; 50*22ce4affSfengbojiang int el_flags; /* Unused. */ 51a9643ea8Slogwang u_int el_runcount; 52a9643ea8Slogwang struct mtx el_lock; 53a9643ea8Slogwang TAILQ_ENTRY(eventhandler_list) el_link; 54a9643ea8Slogwang TAILQ_HEAD(,eventhandler_entry) el_entries; 55a9643ea8Slogwang }; 56a9643ea8Slogwang 57a9643ea8Slogwang #define EHL_LOCK(p) mtx_lock(&(p)->el_lock) 58a9643ea8Slogwang #define EHL_UNLOCK(p) mtx_unlock(&(p)->el_lock) 59a9643ea8Slogwang #define EHL_LOCK_ASSERT(p, x) mtx_assert(&(p)->el_lock, x) 60a9643ea8Slogwang 61a9643ea8Slogwang /* 62a9643ea8Slogwang * Macro to invoke the handlers for a given event. 63a9643ea8Slogwang */ 64a9643ea8Slogwang #define _EVENTHANDLER_INVOKE(name, list, ...) do { \ 65a9643ea8Slogwang struct eventhandler_entry *_ep; \ 66a9643ea8Slogwang struct eventhandler_entry_ ## name *_t; \ 67a9643ea8Slogwang \ 68a9643ea8Slogwang EHL_LOCK_ASSERT((list), MA_OWNED); \ 69a9643ea8Slogwang (list)->el_runcount++; \ 70a9643ea8Slogwang KASSERT((list)->el_runcount > 0, \ 71a9643ea8Slogwang ("eventhandler_invoke: runcount overflow")); \ 72a9643ea8Slogwang CTR0(KTR_EVH, "eventhandler_invoke(\"" __STRING(name) "\")"); \ 73a9643ea8Slogwang TAILQ_FOREACH(_ep, &((list)->el_entries), ee_link) { \ 74a9643ea8Slogwang if (_ep->ee_priority != EHE_DEAD_PRIORITY) { \ 75a9643ea8Slogwang EHL_UNLOCK((list)); \ 76a9643ea8Slogwang _t = (struct eventhandler_entry_ ## name *)_ep; \ 77a9643ea8Slogwang CTR1(KTR_EVH, "eventhandler_invoke: executing %p", \ 78a9643ea8Slogwang (void *)_t->eh_func); \ 79a9643ea8Slogwang _t->eh_func(_ep->ee_arg , ## __VA_ARGS__); \ 80a9643ea8Slogwang EHL_LOCK((list)); \ 81a9643ea8Slogwang } \ 82a9643ea8Slogwang } \ 83a9643ea8Slogwang KASSERT((list)->el_runcount > 0, \ 84a9643ea8Slogwang ("eventhandler_invoke: runcount underflow")); \ 85a9643ea8Slogwang (list)->el_runcount--; \ 86a9643ea8Slogwang if ((list)->el_runcount == 0) \ 87a9643ea8Slogwang eventhandler_prune_list(list); \ 88a9643ea8Slogwang EHL_UNLOCK((list)); \ 89a9643ea8Slogwang } while (0) 90a9643ea8Slogwang 91a9643ea8Slogwang /* 92*22ce4affSfengbojiang * You can optionally use the EVENTHANDLER_LIST and EVENTHANDLER_DIRECT macros 93*22ce4affSfengbojiang * to pre-define a symbol for the eventhandler list. This symbol can be used by 94*22ce4affSfengbojiang * EVENTHANDLER_DIRECT_INVOKE, which has the advantage of not needing to do a 95*22ce4affSfengbojiang * locked search of the global list of eventhandler lists. At least 96*22ce4affSfengbojiang * EVENTHANDLER_LIST_DEFINE must be be used for EVENTHANDLER_DIRECT_INVOKE to 97*22ce4affSfengbojiang * work. EVENTHANDLER_LIST_DECLARE is only needed if the call to 98*22ce4affSfengbojiang * EVENTHANDLER_DIRECT_INVOKE is in a different compilation unit from 99*22ce4affSfengbojiang * EVENTHANDLER_LIST_DEFINE. If the events are even relatively high frequency 100*22ce4affSfengbojiang * it is suggested that you directly define a list for them. 101a9643ea8Slogwang */ 102*22ce4affSfengbojiang #define EVENTHANDLER_LIST_DEFINE(name) \ 103*22ce4affSfengbojiang struct eventhandler_list *_eventhandler_list_ ## name ; \ 104*22ce4affSfengbojiang static void _ehl_init_ ## name (void * ctx __unused) \ 105a9643ea8Slogwang { \ 106*22ce4affSfengbojiang _eventhandler_list_ ## name = eventhandler_create_list(#name); \ 107*22ce4affSfengbojiang } \ 108*22ce4affSfengbojiang SYSINIT(name ## _ehl_init, SI_SUB_EVENTHANDLER, SI_ORDER_ANY, \ 109*22ce4affSfengbojiang _ehl_init_ ## name, NULL); \ 110a9643ea8Slogwang struct __hack 111a9643ea8Slogwang 112*22ce4affSfengbojiang #define EVENTHANDLER_DIRECT_INVOKE(name, ...) do { \ 113*22ce4affSfengbojiang struct eventhandler_list *_el; \ 114*22ce4affSfengbojiang \ 115*22ce4affSfengbojiang _el = _eventhandler_list_ ## name ; \ 116*22ce4affSfengbojiang if (!TAILQ_EMPTY(&_el->el_entries)) { \ 117*22ce4affSfengbojiang EHL_LOCK(_el); \ 118*22ce4affSfengbojiang _EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__); \ 119*22ce4affSfengbojiang } \ 120*22ce4affSfengbojiang } while (0) 121*22ce4affSfengbojiang 122a9643ea8Slogwang #define EVENTHANDLER_DEFINE(name, func, arg, priority) \ 123a9643ea8Slogwang static eventhandler_tag name ## _tag; \ 124a9643ea8Slogwang static void name ## _evh_init(void *ctx) \ 125a9643ea8Slogwang { \ 126a9643ea8Slogwang name ## _tag = EVENTHANDLER_REGISTER(name, func, ctx, \ 127a9643ea8Slogwang priority); \ 128a9643ea8Slogwang } \ 129a9643ea8Slogwang SYSINIT(name ## _evh_init, SI_SUB_CONFIGURE, SI_ORDER_ANY, \ 130a9643ea8Slogwang name ## _evh_init, arg); \ 131a9643ea8Slogwang struct __hack 132a9643ea8Slogwang 133a9643ea8Slogwang #define EVENTHANDLER_INVOKE(name, ...) \ 134a9643ea8Slogwang do { \ 135a9643ea8Slogwang struct eventhandler_list *_el; \ 136a9643ea8Slogwang \ 137a9643ea8Slogwang if ((_el = eventhandler_find_list(#name)) != NULL) \ 138a9643ea8Slogwang _EVENTHANDLER_INVOKE(name, _el , ## __VA_ARGS__); \ 139a9643ea8Slogwang } while (0) 140a9643ea8Slogwang 141a9643ea8Slogwang #define EVENTHANDLER_REGISTER(name, func, arg, priority) \ 142a9643ea8Slogwang eventhandler_register(NULL, #name, func, arg, priority) 143a9643ea8Slogwang 144a9643ea8Slogwang #define EVENTHANDLER_DEREGISTER(name, tag) \ 145a9643ea8Slogwang do { \ 146a9643ea8Slogwang struct eventhandler_list *_el; \ 147a9643ea8Slogwang \ 148a9643ea8Slogwang if ((_el = eventhandler_find_list(#name)) != NULL) \ 149a9643ea8Slogwang eventhandler_deregister(_el, tag); \ 150a9643ea8Slogwang } while(0) 151a9643ea8Slogwang 152*22ce4affSfengbojiang #define EVENTHANDLER_DEREGISTER_NOWAIT(name, tag) \ 153*22ce4affSfengbojiang do { \ 154*22ce4affSfengbojiang struct eventhandler_list *_el; \ 155*22ce4affSfengbojiang \ 156*22ce4affSfengbojiang if ((_el = eventhandler_find_list(#name)) != NULL) \ 157*22ce4affSfengbojiang eventhandler_deregister_nowait(_el, tag); \ 158*22ce4affSfengbojiang } while(0) 159a9643ea8Slogwang 160a9643ea8Slogwang eventhandler_tag eventhandler_register(struct eventhandler_list *list, 161a9643ea8Slogwang const char *name, void *func, void *arg, int priority); 162a9643ea8Slogwang void eventhandler_deregister(struct eventhandler_list *list, 163a9643ea8Slogwang eventhandler_tag tag); 164*22ce4affSfengbojiang void eventhandler_deregister_nowait(struct eventhandler_list *list, 165*22ce4affSfengbojiang eventhandler_tag tag); 166a9643ea8Slogwang struct eventhandler_list *eventhandler_find_list(const char *name); 167a9643ea8Slogwang void eventhandler_prune_list(struct eventhandler_list *list); 168*22ce4affSfengbojiang struct eventhandler_list *eventhandler_create_list(const char *name); 169a9643ea8Slogwang 170a9643ea8Slogwang #ifdef VIMAGE 171a9643ea8Slogwang typedef void (*vimage_iterator_func_t)(void *, ...); 172a9643ea8Slogwang 173a9643ea8Slogwang eventhandler_tag vimage_eventhandler_register(struct eventhandler_list *list, 174a9643ea8Slogwang const char *name, void *func, void *arg, int priority, 175a9643ea8Slogwang vimage_iterator_func_t); 176a9643ea8Slogwang #endif 177a9643ea8Slogwang 178a9643ea8Slogwang /* 179a9643ea8Slogwang * Standard system event queues. 180a9643ea8Slogwang */ 181a9643ea8Slogwang 182a9643ea8Slogwang /* Generic priority levels */ 183a9643ea8Slogwang #define EVENTHANDLER_PRI_FIRST 0 184a9643ea8Slogwang #define EVENTHANDLER_PRI_ANY 10000 185a9643ea8Slogwang #define EVENTHANDLER_PRI_LAST 20000 186a9643ea8Slogwang 187a9643ea8Slogwang /* Shutdown events */ 188a9643ea8Slogwang typedef void (*shutdown_fn)(void *, int); 189a9643ea8Slogwang 190a9643ea8Slogwang #define SHUTDOWN_PRI_FIRST EVENTHANDLER_PRI_FIRST 191a9643ea8Slogwang #define SHUTDOWN_PRI_DEFAULT EVENTHANDLER_PRI_ANY 192a9643ea8Slogwang #define SHUTDOWN_PRI_LAST EVENTHANDLER_PRI_LAST 193a9643ea8Slogwang 194a9643ea8Slogwang EVENTHANDLER_DECLARE(shutdown_pre_sync, shutdown_fn); /* before fs sync */ 195a9643ea8Slogwang EVENTHANDLER_DECLARE(shutdown_post_sync, shutdown_fn); /* after fs sync */ 196a9643ea8Slogwang EVENTHANDLER_DECLARE(shutdown_final, shutdown_fn); 197a9643ea8Slogwang 198a9643ea8Slogwang /* Power state change events */ 199a9643ea8Slogwang typedef void (*power_change_fn)(void *); 200a9643ea8Slogwang EVENTHANDLER_DECLARE(power_resume, power_change_fn); 201a9643ea8Slogwang EVENTHANDLER_DECLARE(power_suspend, power_change_fn); 202a9643ea8Slogwang EVENTHANDLER_DECLARE(power_suspend_early, power_change_fn); 203a9643ea8Slogwang 204a9643ea8Slogwang /* Low memory event */ 205a9643ea8Slogwang typedef void (*vm_lowmem_handler_t)(void *, int); 206a9643ea8Slogwang #define LOWMEM_PRI_DEFAULT EVENTHANDLER_PRI_FIRST 207a9643ea8Slogwang EVENTHANDLER_DECLARE(vm_lowmem, vm_lowmem_handler_t); 208a9643ea8Slogwang 209a9643ea8Slogwang /* Root mounted event */ 210a9643ea8Slogwang typedef void (*mountroot_handler_t)(void *); 211a9643ea8Slogwang EVENTHANDLER_DECLARE(mountroot, mountroot_handler_t); 212a9643ea8Slogwang 213a9643ea8Slogwang /* File system mount events */ 214a9643ea8Slogwang struct mount; 215a9643ea8Slogwang struct vnode; 216a9643ea8Slogwang struct thread; 217a9643ea8Slogwang typedef void (*vfs_mounted_notify_fn)(void *, struct mount *, struct vnode *, 218a9643ea8Slogwang struct thread *); 219a9643ea8Slogwang typedef void (*vfs_unmounted_notify_fn)(void *, struct mount *, 220a9643ea8Slogwang struct thread *); 221a9643ea8Slogwang EVENTHANDLER_DECLARE(vfs_mounted, vfs_mounted_notify_fn); 222a9643ea8Slogwang EVENTHANDLER_DECLARE(vfs_unmounted, vfs_unmounted_notify_fn); 223a9643ea8Slogwang 224a9643ea8Slogwang /* 225a9643ea8Slogwang * Process events 226a9643ea8Slogwang * process_fork and exit handlers are called without Giant. 227a9643ea8Slogwang * exec handlers are called with Giant, but that is by accident. 228a9643ea8Slogwang */ 229a9643ea8Slogwang struct proc; 230a9643ea8Slogwang struct image_params; 231a9643ea8Slogwang 232a9643ea8Slogwang typedef void (*exitlist_fn)(void *, struct proc *); 233a9643ea8Slogwang typedef void (*forklist_fn)(void *, struct proc *, struct proc *, int); 234a9643ea8Slogwang typedef void (*execlist_fn)(void *, struct proc *, struct image_params *); 235a9643ea8Slogwang typedef void (*proc_ctor_fn)(void *, struct proc *); 236a9643ea8Slogwang typedef void (*proc_dtor_fn)(void *, struct proc *); 237a9643ea8Slogwang typedef void (*proc_init_fn)(void *, struct proc *); 238a9643ea8Slogwang typedef void (*proc_fini_fn)(void *, struct proc *); 239a9643ea8Slogwang EVENTHANDLER_DECLARE(process_ctor, proc_ctor_fn); 240a9643ea8Slogwang EVENTHANDLER_DECLARE(process_dtor, proc_dtor_fn); 241a9643ea8Slogwang EVENTHANDLER_DECLARE(process_init, proc_init_fn); 242a9643ea8Slogwang EVENTHANDLER_DECLARE(process_fini, proc_fini_fn); 243a9643ea8Slogwang EVENTHANDLER_DECLARE(process_exit, exitlist_fn); 244a9643ea8Slogwang EVENTHANDLER_DECLARE(process_fork, forklist_fn); 245a9643ea8Slogwang EVENTHANDLER_DECLARE(process_exec, execlist_fn); 246a9643ea8Slogwang 247a9643ea8Slogwang /* 248a9643ea8Slogwang * application dump event 249a9643ea8Slogwang */ 250a9643ea8Slogwang typedef void (*app_coredump_start_fn)(void *, struct thread *, char *name); 251a9643ea8Slogwang typedef void (*app_coredump_progress_fn)(void *, struct thread *td, int byte_count); 252a9643ea8Slogwang typedef void (*app_coredump_finish_fn)(void *, struct thread *td); 253a9643ea8Slogwang typedef void (*app_coredump_error_fn)(void *, struct thread *td, char *msg, ...); 254a9643ea8Slogwang 255a9643ea8Slogwang EVENTHANDLER_DECLARE(app_coredump_start, app_coredump_start_fn); 256a9643ea8Slogwang EVENTHANDLER_DECLARE(app_coredump_progress, app_coredump_progress_fn); 257a9643ea8Slogwang EVENTHANDLER_DECLARE(app_coredump_finish, app_coredump_finish_fn); 258a9643ea8Slogwang EVENTHANDLER_DECLARE(app_coredump_error, app_coredump_error_fn); 259a9643ea8Slogwang 260a9643ea8Slogwang typedef void (*thread_ctor_fn)(void *, struct thread *); 261a9643ea8Slogwang typedef void (*thread_dtor_fn)(void *, struct thread *); 262a9643ea8Slogwang typedef void (*thread_fini_fn)(void *, struct thread *); 263a9643ea8Slogwang typedef void (*thread_init_fn)(void *, struct thread *); 264a9643ea8Slogwang EVENTHANDLER_DECLARE(thread_ctor, thread_ctor_fn); 265a9643ea8Slogwang EVENTHANDLER_DECLARE(thread_dtor, thread_dtor_fn); 266a9643ea8Slogwang EVENTHANDLER_DECLARE(thread_init, thread_init_fn); 267a9643ea8Slogwang EVENTHANDLER_DECLARE(thread_fini, thread_fini_fn); 268a9643ea8Slogwang 269a9643ea8Slogwang typedef void (*uma_zone_chfn)(void *); 270a9643ea8Slogwang EVENTHANDLER_DECLARE(nmbclusters_change, uma_zone_chfn); 271a9643ea8Slogwang EVENTHANDLER_DECLARE(nmbufs_change, uma_zone_chfn); 272a9643ea8Slogwang EVENTHANDLER_DECLARE(maxsockets_change, uma_zone_chfn); 273a9643ea8Slogwang 274a9643ea8Slogwang /* Kernel linker file load and unload events */ 275a9643ea8Slogwang struct linker_file; 276a9643ea8Slogwang typedef void (*kld_load_fn)(void *, struct linker_file *); 277a9643ea8Slogwang typedef void (*kld_unload_fn)(void *, const char *, caddr_t, size_t); 278a9643ea8Slogwang typedef void (*kld_unload_try_fn)(void *, struct linker_file *, int *); 279a9643ea8Slogwang EVENTHANDLER_DECLARE(kld_load, kld_load_fn); 280a9643ea8Slogwang EVENTHANDLER_DECLARE(kld_unload, kld_unload_fn); 281a9643ea8Slogwang EVENTHANDLER_DECLARE(kld_unload_try, kld_unload_try_fn); 282a9643ea8Slogwang 283a9643ea8Slogwang /* Generic graphics framebuffer interface */ 284a9643ea8Slogwang struct fb_info; 285a9643ea8Slogwang typedef void (*register_framebuffer_fn)(void *, struct fb_info *); 286a9643ea8Slogwang typedef void (*unregister_framebuffer_fn)(void *, struct fb_info *); 287a9643ea8Slogwang EVENTHANDLER_DECLARE(register_framebuffer, register_framebuffer_fn); 288a9643ea8Slogwang EVENTHANDLER_DECLARE(unregister_framebuffer, unregister_framebuffer_fn); 289a9643ea8Slogwang 290e7145e36Sfengbojiang(姜凤波) /* Veto ada attachment */ 291e7145e36Sfengbojiang(姜凤波) struct cam_path; 292e7145e36Sfengbojiang(姜凤波) struct ata_params; 293e7145e36Sfengbojiang(姜凤波) typedef void (*ada_probe_veto_fn)(void *, struct cam_path *, 294e7145e36Sfengbojiang(姜凤波) struct ata_params *, int *); 295e7145e36Sfengbojiang(姜凤波) EVENTHANDLER_DECLARE(ada_probe_veto, ada_probe_veto_fn); 296e7145e36Sfengbojiang(姜凤波) 297*22ce4affSfengbojiang /* Swap device events */ 298*22ce4affSfengbojiang struct swdevt; 299*22ce4affSfengbojiang typedef void (*swapon_fn)(void *, struct swdevt *); 300*22ce4affSfengbojiang typedef void (*swapoff_fn)(void *, struct swdevt *); 301*22ce4affSfengbojiang EVENTHANDLER_DECLARE(swapon, swapon_fn); 302*22ce4affSfengbojiang EVENTHANDLER_DECLARE(swapoff, swapoff_fn); 303*22ce4affSfengbojiang 304*22ce4affSfengbojiang /* newbus device events */ 305*22ce4affSfengbojiang enum evhdev_detach { 306*22ce4affSfengbojiang EVHDEV_DETACH_BEGIN, /* Before detach() is called */ 307*22ce4affSfengbojiang EVHDEV_DETACH_COMPLETE, /* After detach() returns 0 */ 308*22ce4affSfengbojiang EVHDEV_DETACH_FAILED /* After detach() returns err */ 309*22ce4affSfengbojiang }; 310*22ce4affSfengbojiang typedef void (*device_attach_fn)(void *, device_t); 311*22ce4affSfengbojiang typedef void (*device_detach_fn)(void *, device_t, enum evhdev_detach); 312*22ce4affSfengbojiang EVENTHANDLER_DECLARE(device_attach, device_attach_fn); 313*22ce4affSfengbojiang EVENTHANDLER_DECLARE(device_detach, device_detach_fn); 314*22ce4affSfengbojiang 315*22ce4affSfengbojiang /* Interface address addition and removal event */ 316*22ce4affSfengbojiang struct ifaddr; 317*22ce4affSfengbojiang typedef void (*rt_addrmsg_fn)(void *, struct ifaddr *, int); 318*22ce4affSfengbojiang EVENTHANDLER_DECLARE(rt_addrmsg, rt_addrmsg_fn); 319*22ce4affSfengbojiang 320a9643ea8Slogwang #endif /* _SYS_EVENTHANDLER_H_ */ 321