FEATURES: document various missed changes
[unleashed/lotheac.git] / include / sys / sysevent_impl.h
blob117452765f598e12e9fc52235f1059a6791c5f5a
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
26 #ifndef _SYS_SYSEVENT_IMPL_H
27 #define _SYS_SYSEVENT_IMPL_H
29 #include <sys/nvpair.h>
30 #include <sys/id_space.h>
31 #include <sys/door.h>
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
37 typedef uint64_t se_data_t;
40 * The following data structure assist in loading and extracting event
41 * header and attribute data into contiguous memory. Access to all typed
42 * data done so on 64-bit boundaries. *Do Not* alter any of the structures
43 * defined below without thorough thought and testing.
46 /* Attribute name */
47 typedef struct se_name {
48 int32_t name_sz;
49 int32_t name_pad;
50 se_data_t name; /* 64-bit aligned offset */
51 } se_name_t;
53 /* Attribute value */
54 typedef struct se_value {
55 int32_t value_type; /* data type */
56 int32_t value_sz;
57 se_data_t value; /* data value - 64-bit aligned offset */
58 } se_value_t;
60 /* sysevent internal attribute name-value pair stored in contiguous memory */
61 typedef struct sysevent_attr_impl {
62 int32_t se_attr_sz; /* Size of attribute data */
63 int32_t se_attr_pad; /* pad */
64 se_data_t se_attr_name; /* name of data attribute */
65 se_data_t se_attr_val; /* value and type of data */
66 } sysevent_attr_impl_t;
68 /* Attribute list states */
69 #define ATTR_DETACHED 0
70 #define ATTR_ATTACHED 1
73 * The following type definitions describe a sysevent object that is
74 * generated by a call to sysevent_alloc and sent to userland.
78 * sysevent event header information -
79 * contained in every event generated. The header and the event
80 * must remain 64-bit aligned. The header, up to the attribute
81 * offset, can be contained in a single cache line.
83 typedef struct sysevent_hdr {
84 sysevent_id_t se_id; /* unique identifier */
85 uint32_t se_version; /* version of this data structure */
86 uint32_t se_flag;
87 uint32_t se_class; /* event class id - reserved */
88 uint32_t se_subclass; /* event subclass id - reserved */
89 int32_t se_payload_sz; /* size of attr data + strings */
90 uint16_t se_subclass_off; /* offset to subclass string */
91 uint16_t se_pub_off; /* offset to publisher string */
92 uint64_t se_attr_off; /* pointer or offset to attr data */
93 } sysevent_hdr_t;
95 /* sysevent event buffer - 64-bit aligned offsets */
96 typedef struct sys_event_impl {
97 sysevent_hdr_t se_header;
98 se_data_t se_class_name; /* class string in contig memory */
99 se_data_t se_subclass_name; /* subclass string in contig memory */
100 se_data_t se_pub; /* publisher string in contig mem */
101 se_data_t se_attr_buf; /* contiguous attribute memory */
102 } sysevent_impl_t;
104 /* Helpful defines */
105 #define seh_version se_header.se_version
106 #define seh_class se_header.se_class
107 #define seh_subclass se_header.se_subclass
108 #define seh_seq se_header.se_id.eid_seq
109 #define seh_time se_header.se_id.eid_ts
110 #define seh_subclass_off se_header.se_subclass_off
111 #define seh_pub_off se_header.se_pub_off
112 #define seh_attr_off se_header.se_attr_off
113 #define seh_payload_sz se_header.se_payload_sz
114 #define seh_flag se_header.se_flag
116 /* Event buffer version */
117 #define SYS_EVENT_VERSION 0
119 /* Event buffer flags */
120 #define SE_PACKED_BUF 1
122 #define SYSEVENT_IMPL(ev) ((sysevent_impl_t *)(void *)(ev))
123 #define SE_VERSION(ev) (SYSEVENT_IMPL(ev)->seh_version)
124 #define SE_CLASS(ev) (SYSEVENT_IMPL(ev)->seh_class)
125 #define SE_SUBCLASS(ev) (SYSEVENT_IMPL(ev)->seh_subclass)
126 #define SE_SEQ(ev) (SYSEVENT_IMPL(ev)->seh_seq)
127 #define SE_TIME(ev) (SYSEVENT_IMPL(ev)->seh_time)
128 #define SE_SUBCLASS_OFF(ev) (SYSEVENT_IMPL(ev)->seh_subclass_off)
129 #define SE_PUB_OFF(ev) (SYSEVENT_IMPL(ev)->seh_pub_off)
130 #define SE_PAYLOAD_SZ(ev) (SYSEVENT_IMPL(ev)->seh_payload_sz)
131 #define SE_FLAG(ev) (SYSEVENT_IMPL(ev)->seh_flag)
132 #define SE_SIZE(ev) (sizeof (sysevent_impl_t) + SE_PAYLOAD_SZ(ev))
133 #define SE_CLASS_NAME(ev) ((char *)&(SYSEVENT_IMPL(ev)->se_class_name))
134 #define SE_SUBCLASS_NAME(ev) ((char *)((caddr_t)(ev) + SE_SUBCLASS_OFF(ev)))
135 #define SE_PUB_NAME(ev) ((char *)((caddr_t)(ev) + SE_PUB_OFF(ev)))
138 * Attribute data can be stored in contiguous memory or
139 * as a list of attribute data elements. The storage format is determined
140 * by the SE_PACKED_BUF flag in the event buffer flags.
144 /* 64-bit boundary alignment function */
145 #define SE_ALIGN(x) ((((ulong_t)x) + 7ul) & ~7ul)
147 /* Access to unpacked attribute list */
148 #define SE_ATTR_PTR(ev) (SYSEVENT_IMPL(ev)->seh_attr_off)
150 /* Offset to packed attribute data */
151 #define SE_ATTR_OFF(ev) SE_PUB_OFF(ev) + SE_ALIGN(strlen(SE_PUB_NAME(ev)) + 1)
153 /* syseventd door */
154 #define LOGEVENT_DOOR_UPCALL "/var/run/sysevent_door"
157 * door upcall data structures
159 typedef struct log_event_upcall_arg {
160 int32_t retcode;
161 int32_t pad;
162 sysevent_impl_t buf;
163 } log_event_upcall_arg_t;
165 typedef struct log_eventq {
166 struct log_eventq *next;
167 log_event_upcall_arg_t arg;
168 } log_eventq_t;
170 /* Syseventd Channel structures */
172 #define MAX_CHAN 256 /* Maximum channels per system */
173 #define MAX_SUBSCRIBERS 100 /* Maximum subscribers per channel */
174 #define MAX_PUBLISHERS 1 /* Maximum publishers per channel */
177 * Channel-based subscription structures
180 /* Class hashing defines */
181 #define CLASS_HASH_SZ 63
182 #define CLASS_HASH(class_name) ((hash_func(class_name) \
183 % CLASS_HASH_SZ) + 1)
184 #define CHAN_HASH_SZ 32
186 typedef struct subclass_lst {
187 struct subclass_lst *sl_next;
188 char *sl_name;
189 uchar_t sl_num[MAX_SUBSCRIBERS + 1];
190 } subclass_lst_t;
192 typedef struct class_lst {
193 struct class_lst *cl_next;
194 char *cl_name;
195 struct subclass_lst *cl_subclass_list;
196 } class_lst_t;
198 /* User/Kernel Structure to pass event registration modctl data */
199 typedef struct se_pubsub {
200 uint32_t ps_buflen;
201 uint32_t ps_channel_name_len;
202 uint32_t ps_id;
203 uint32_t ps_op;
204 uint32_t ps_type;
205 } se_pubsub_t;
207 /* op defines */
208 #define SE_REGISTER 0
209 #define SE_UNREGISTER 1
210 #define SE_CLEANUP 2
211 #define SE_OPEN_REGISTRATION 3
212 #define SE_CLOSE_REGISTRATION 4
213 #define SE_BIND_REGISTRATION 5
214 #define SE_UNBIND_REGISTRATION 6
215 #define SE_GET_REGISTRATION 7
217 /* type defines */
218 #define SUBSCRIBER 0
219 #define PUBLISHER 1
221 /* nvpair names */
222 #define CLASS_NAME "class"
224 #ifdef _KERNEL
226 typedef struct sysevent_channel_descriptor {
227 char *scd_channel_name; /* Name of channel */
228 struct sysevent_channel_descriptor *scd_next;
229 int scd_ref_cnt; /* Reference count of channel opens */
230 id_space_t *scd_subscriber_cache; /* cache of subscriber ids */
231 id_space_t *scd_publisher_cache; /* cache of publisher ids */
232 uchar_t scd_subscriber_ids[MAX_SUBSCRIBERS + 1]; /* used sub ids */
233 uchar_t scd_publisher_ids[MAX_PUBLISHERS + 1]; /* used pub ids */
234 class_lst_t *scd_class_list_tbl[CLASS_HASH_SZ + 1];
235 } sysevent_channel_descriptor_t;
238 * log_sysevent private interfaces
240 extern void log_event_init(void);
241 extern void log_sysevent_flushq(int, uint_t);
242 extern int log_sysevent_filename(char *);
243 extern int log_usr_sysevent(sysevent_t *, int, sysevent_id_t *);
244 extern int log_sysevent_copyout_data(sysevent_id_t *, size_t, caddr_t);
245 extern int log_sysevent_free_data(sysevent_id_t *);
246 extern int log_sysevent_register(char *, char *, se_pubsub_t *);
247 extern uint64_t log_sysevent_new_id(void);
250 * Structures and definitions for general purpose event channels
253 /* Limits */
254 #define EVCH_MAX_CHANNELS 1024
255 #define EVCH_MAX_BINDS_PER_CHANNEL 512
256 #define EVCH_MAX_SUBSCRIPTIONS 32
257 #define EVCH_SUBPOOLFACT 8
258 #define EVCH_DEFAULT_EVENTS 2000
259 #define EVCH_MAX_TRY_DELIVERY 3
261 /* Linkage element for evch_dlist_t lists */
262 typedef struct evch_dlelem {
263 struct evch_dlelem *dl_next;
264 struct evch_dlelem *dl_prev;
265 } evch_dlelem_t;
267 /* List head */
268 typedef struct {
269 evch_dlelem_t dh_head;
270 int dh_count;
271 } evch_dlist_t;
273 /* Placeholder for elements in a evch_squeue_t queue */
274 typedef struct evch_qelem {
275 struct evch_qelem *q_next;
276 void *q_objref;
277 size_t q_objsize;
278 } evch_qelem_t;
280 /* Queue head data */
281 typedef struct {
282 evch_qelem_t *sq_head;
283 evch_qelem_t *sq_tail;
284 uint32_t sq_count;
285 uint32_t sq_highwm;
286 } evch_squeue_t;
289 * Defines for event queue routines
291 #define EVQ_IGNORE 1
292 #define EVQ_DELIVER 2
294 #define EVQ_CONT 0
295 #define EVQ_AGAIN 1
296 #define EVQ_SLEEP 2
298 /* Call back routine typedefs */
299 typedef int (*filter_f)(void *, void *);
300 typedef int (*deliver_f)(void *, void *);
301 typedef int (*kerndlv_f)(void *, void *);
302 typedef void (*destr_f)(void *, void *);
303 typedef int (*compare_f)(evch_dlelem_t *, char *);
306 * Event structure handled by evch_evq_* functions. Sysevent type events are
307 * stored as the payload.
309 typedef struct {
310 uint32_t ge_size; /* Total size of event structure */
311 uint32_t ge_refcount; /* No of queues event is linked to */
312 destr_f ge_destruct; /* Destructor for event structure */
313 uint32_t *ge_dstcookie; /* Cookie for destructor function */
314 uchar_t ge_payload[1]; /* Placeholder for event data */
315 } evch_gevent_t;
318 * Event queue descriptor
320 typedef struct {
321 evch_squeue_t eq_eventq; /* Protected by eq_dtmutex */
322 kt_did_t eq_thrid; /* Id delivery thread */
323 kmutex_t eq_queuemx; /* Protect. of this struct and ev q */
324 kcondvar_t eq_thrsleepcv; /* Delivery thread sleeps on empty q */
325 int eq_dactive; /* Event delivery is in progress */
326 kcondvar_t eq_dactivecv; /* Unsubscr. has to wait on this */
327 evch_dlist_t eq_subscr; /* Chain of all evch_evqsub_t */
328 uint32_t eq_nsleep; /* Statistic: Publisher set to sleep */
329 int eq_holdmode; /* Hold event delivery */
330 evch_gevent_t *eq_curevent; /* Event currently beeing delivered */
331 evch_qelem_t *eq_nextev; /* For iterating over events in a q */
332 kcondvar_t eq_onholdcv; /* To signal hold mode of deliv. thr. */
333 uchar_t eq_tabortflag; /* Request to abort delivery thread */
334 } evch_eventq_t;
337 * Event queue per subscriber structure
339 typedef struct {
340 evch_dlelem_t su_link;
341 filter_f su_filter; /* Event filter function pointer */
342 void *su_fcookie; /* cookie for event filter */
343 deliver_f su_callb; /* Event delivery callback */
344 void *su_cbcookie; /* callback cookie */
345 } evch_evqsub_t;
347 /* Eveny delivery type */
348 #define EVCH_DELKERN 1 /* Kernel event delivery */
349 #define EVCH_DELDOOR 2 /* User event delivery via doors */
352 * Per channel subscriber data structure. Chained in a linked list to an
353 * event channel and to a binding.
355 typedef struct chsubd {
356 evch_dlelem_t sd_link; /* Links all subscribers of this ch. */
357 struct chsubd *sd_subnxt; /* Links all subscr. for a binding */
358 char *sd_ident; /* Subscriber identifier */
359 evch_eventq_t *sd_queue; /* Event queue for this subscriber */
360 evch_evqsub_t *sd_msub; /* Main event queue subscr. */
361 char *sd_classname; /* Filter criteria */
362 size_t sd_clnsize; /* Size of sd_classname buffer */
363 evch_evqsub_t *sd_ssub; /* Subscriber queue subscr. */
364 int sd_type; /* Type of event delivery */
365 kerndlv_f sd_callback; /* Callback for kernel delivery */
366 void *sd_cbcookie; /* Cookie for kernel delivery */
367 door_handle_t sd_door; /* Door handle for user delivery */
368 int sd_active; /* Subscription is in use indicator */
369 pid_t sd_pid; /* PID of subscribing process */
370 uint8_t sd_persist; /* Persistent user land subscription */
371 uint8_t sd_dump; /* Dump with sysevent_evc_walk_* */
372 } evch_subd_t;
375 * General purpose event channel descriptor structure. This is the main
376 * structure for event subscribing, publishing, delivery to/from an event
377 * channel.
379 typedef struct {
380 evch_dlelem_t ch_link; /* Must be first elem. of structure */
381 char *ch_name; /* Channel name */
382 size_t ch_namelen; /* Length of channel name buffer */
383 kmutex_t ch_mutex; /* To protect this structure */
384 evch_eventq_t *ch_queue; /* Publisher event queue */
385 evch_dlist_t ch_subscr; /* List of subscr. data (evch_subd_t) */
386 uint32_t ch_bindings; /* No of bindings to this channel */
387 int ch_maxbinds; /* Maximum number of binds */
388 uid_t ch_uid; /* Creators effective user id */
389 gid_t ch_gid; /* Creators effective group id */
390 kmutex_t ch_pubmx; /* Mutex for ch_pubcv and ch_nevents */
391 kcondvar_t ch_pubcv; /* To set publisher to sleep */
392 uint32_t ch_nevents; /* Current number of events */
393 uint32_t ch_maxev; /* Maximum number of events */
394 int ch_maxsubscr; /* Maximum number of subscriptions */
395 int ch_holdpend; /* Hold pending events mode if != 0 */
396 time_t ch_ctime; /* Channel creation time */
397 nvlist_t *ch_propnvl; /* Channel properties nvlist */
398 int64_t ch_propnvlgen; /* Properties generation number */
399 } evch_chan_t;
402 * Channel binding structure. Allocated per binding to a channel. Protected
403 * by locking the channel structure
405 typedef struct {
406 evch_chan_t *bd_channel;
407 evch_subd_t *bd_sublst; /* chain of all subscriptions */
408 } evch_bind_t;
411 * Structure to keep a snapshot of all events of a channel
413 typedef struct {
414 evch_eventq_t *sn_queue; /* Event queue with snapshot of ev's */
415 sysevent_impl_t *sn_nxtev; /* Pointer to find next event */
416 } evchanq_t;
418 /* Project private interfaces */
419 extern evchan_t *evch_usrchanopen(const char *name, uint32_t flags, int *err);
420 extern void evch_usrchanclose(evchan_t *cbp);
421 extern sysevent_impl_t *evch_usrallocev(size_t evsize, uint32_t flags);
422 extern void evch_usrfreeev(sysevent_impl_t *ev);
423 extern int evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags);
424 extern int evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class,
425 int d, uint32_t flags);
426 extern int evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value);
427 extern int evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value);
428 extern void evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flag);
429 extern int evch_usrgetchnames(char *buf, size_t size);
430 extern int evch_usrgetchdata(char *chname, void *buf, size_t size);
431 extern void evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl);
432 extern int evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp);
434 extern void sysevent_evc_init();
435 extern void sysevent_evc_thrinit();
436 extern evchanq_t *sysevent_evc_walk_init(evchan_t *, char *);
437 extern sysevent_t *sysevent_evc_walk_step(evchanq_t *);
438 extern void sysevent_evc_walk_fini(evchanq_t *);
439 extern char *sysevent_evc_event_attr(sysevent_t *, size_t *);
441 #endif /* _KERNEL */
444 * Structures and limits to deliver channel data to syseventadm
446 #define EVCH_MAX_DATA_SIZE (1024 * 1024)
448 typedef struct {
449 uint32_t sb_nextoff; /* Offset to next subscr info struct */
450 uint32_t sb_stroff; /* Offset to strings */
451 uint32_t sb_clnamoff; /* Offset of class in sb_strings */
452 uint32_t sb_pid; /* Subscriber process id */
453 uint32_t sb_nevents; /* Current no of event in sub q */
454 uint32_t sb_evhwm; /* High watermark of sub q */
455 uint32_t sb_persist; /* != 0 if subscription persists */
456 uint32_t sb_status; /* != 0 if subscription is inactive */
457 uint32_t sb_active; /* > 0 if subscription is in use */
458 uint32_t sb_dump; /* != 0 if sub will be dumped */
459 char sb_strings[1]; /* String space for subid and class */
460 } sev_subinfo_t;
462 typedef struct {
463 uint32_t cd_version; /* Version of this structure */
464 uint32_t cd_suboffs; /* Offset of subscriber info struct */
465 uint64_t cd_ctime; /* Creation time */
466 uint32_t cd_uid; /* User id */
467 uint32_t cd_gid; /* Owner group id */
468 uint32_t cd_perms; /* Permission bits */
469 uint32_t cd_maxev; /* Max number of events */
470 uint32_t cd_evhwm; /* High watermark of main event queue */
471 uint32_t cd_nevents; /* current no of events in main ev q */
472 uint32_t cd_maxsub; /* Max number of subscriptions */
473 uint32_t cd_nsub; /* Current number of subscriptions */
474 uint32_t cd_maxbinds; /* Max number of binds */
475 uint32_t cd_nbinds; /* Current number of binds */
476 uint32_t cd_holdpend; /* != 0 when HOLDPEND mode is set */
477 uint32_t cd_limev; /* Limit of events per channel */
478 sev_subinfo_t cd_subinfo[1]; /* Per subscriber data */
479 } sev_chinfo_t;
482 * Project private flags for sysevent_evc_subscribe. Bits 0 to 7 are reserved
483 * for the consolidation private interface, so we must use bits 8-15 here.
485 #define EVCH_SUB_DUMP (0x01 << 8)
488 * Permission flags
490 #define EVCH_PUB 0x0004 /* wants to publish events */
491 #define EVCH_SUB 0x0008 /* wants to subscribe to channel */
493 #define EVCH_SUBU 0x0001 /* Subscribing allowed for uid */
494 #define EVCH_PUBU 0x0002 /* Publishing allowed for uid */
495 #define EVCH_PSUSR 0x0003 /* EVCH_SUBU + EVCH_PUBU */
496 #define EVCH_SUBG 0x0004 /* Subscribing allowed for gid */
497 #define EVCH_PUBG 0x0008 /* Publishing allowed for gid */
498 #define EVCH_PSGRP 0x000C /* EVCH_SUBG + EVCH_PUBG */
499 #define EVCH_SUBO 0x0010 /* Subscribing allowed to all users */
500 #define EVCH_PUBO 0x0020 /* Publishing allowed to all users */
501 #define EVCH_PSOTH 0x0030 /* EVCH_SUBO + EVCH_PUBO */
502 #define EVCH_PSALL 0x003f /* Mask of all permission bits */
505 * Sysevent driver ioctls
507 #define SEV_BASE 0x53455600
508 #define SEV_PUBLISH SEV_BASE | 0x01
509 #define SEV_CHAN_OPEN SEV_BASE | 0x02
510 #define SEV_CHAN_CONTROL SEV_BASE | 0x03
511 #define SEV_SUBSCRIBE SEV_BASE | 0x04
512 #define SEV_UNSUBSCRIBE SEV_BASE | 0x05
513 #define SEV_CHANNAMES SEV_BASE | 0x06
514 #define SEV_CHANDATA SEV_BASE | 0x07
515 #define SEV_SETPROPNVL SEV_BASE | 0x08
516 #define SEV_GETPROPNVL SEV_BASE | 0x09
518 #define DEVSYSEVENT "/dev/sysevent"
519 #define DEVICESYSEVENT "/devices/pseudo/sysevent@0:sysevent"
522 * Maximum allowed binding handles
523 * It's a limit required by bitmap algorithm design (see sys/bitmap.h).
524 * Use pack(4) to make sizeof structs be the same on x86 and amd64.
526 #define SYSEVENT_MINOR_MAX SHRT_MAX
528 #if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
529 #pragma pack(4)
530 #endif
532 /* copyin/copyout data */
533 typedef struct box {
534 uint64_t name; /* pointer to something */
535 uint32_t len;
536 } sev_box_t;
538 typedef struct bind_args {
539 sev_box_t chan_name;
540 uint32_t flags;
541 } sev_bind_args_t;
543 typedef struct control_args {
544 uint32_t cmd;
545 uint32_t value;
546 } sev_control_args_t;
548 typedef struct publish_args {
549 sev_box_t ev;
550 uint32_t flags;
551 } sev_publish_args_t;
553 typedef struct subscribe_args {
554 sev_box_t sid;
555 sev_box_t class_info;
556 int door_desc;
557 uint32_t flags;
558 } sev_subscribe_args_t;
560 typedef struct unsubscribe_args {
561 sev_box_t sid;
562 } sev_unsubscribe_args_t;
564 typedef struct chandata {
565 sev_box_t in_data;
566 sev_box_t out_data;
567 } sev_chandata_args_t;
569 typedef struct propnvl_args {
570 sev_box_t packednvl; /* input and output */
571 int64_t generation; /* output on get operation */
572 } sev_propnvl_args_t;
574 #if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
575 #pragma pack()
576 #endif
578 #ifdef __cplusplus
580 #endif
582 #endif /* _SYS_SYSEVENT_IMPL_H */