Mercurial > illumos > illumos-gate
changeset 11102:b91faef0c984
PSARC/2009/554 door_xcreate - extended door creation interface for private doors
PSARC/2009/573 libfmevent - external subscriptions to FMA protocol events
PSARC/2009/574 GPEC interface changes and additions
6893144 add door_xcreate for creating private doors with per-door thread creation control
6896220 sysevent_evc_xsubscribe and other GPEC modifications
6900975 sysevent_evc_{unbind,unsubscribe} off-by-one in subscriber list traversal
6868087 facility to allow external processes to subscribe to FMA protocol events
6896205 fmd module to forward selected protocol events for external subscription
line wrap: on
line diff
--- a/usr/src/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c Thu Nov 19 15:28:11 2009 +1100 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <libsysevent.h> #include <stdio.h> @@ -42,7 +40,7 @@ for (;;) { if (sysevent_evc_publish(ch, "class_dtest", "subclass_dtest", "vendor_dtest", "publisher_dtest", NULL, EVCH_SLEEP) != 0) { - sysevent_evc_unbind(ch); + (void) sysevent_evc_unbind(ch); (void) fprintf(stderr, "failed to publisth sysevent\n"); return (1); }
--- a/usr/src/cmd/fm/fmd/common/fmd_sysevent.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/cmd/fm/fmd/common/fmd_sysevent.c Thu Nov 19 15:28:11 2009 +1100 @@ -533,8 +533,8 @@ sysev_fini(fmd_hdl_t *hdl) { if (strcmp(sysev_channel, FM_ERROR_CHAN) != 0) { - sysevent_evc_unsubscribe(sysev_evc, sysev_sid); - sysevent_evc_unbind(sysev_evc); + (void) sysevent_evc_unsubscribe(sysev_evc, sysev_sid); + (void) sysevent_evc_unbind(sysev_evc); } if (fmd.d_sysev_hdl != NULL)
--- a/usr/src/cmd/fm/fminject/common/inj_main.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/cmd/fm/fminject/common/inj_main.c Thu Nov 19 15:28:11 2009 +1100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/sysevent/eventdefs.h> #include <sys/fm/util.h> #include <fm/fmd_log.h> @@ -80,7 +77,7 @@ static void sev_close(void *arg) { - sysevent_evc_unbind(arg); + (void) sysevent_evc_unbind(arg); } static inj_mode_ops_t sysevent_ops = {
--- a/usr/src/cmd/fm/modules/common/Makefile Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/cmd/fm/modules/common/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -27,6 +27,9 @@ disk-monitor \ disk-transport \ eversholt \ + ext-event-transport \ + fabric-xlate \ + fdd-msg \ io-retire \ ip-transport \ sensor-transport \ @@ -34,8 +37,6 @@ sp-monitor \ syslog-msgs \ zfs-diagnosis \ - zfs-retire \ - fdd-msg \ - fabric-xlate + zfs-retire include ../../Makefile.subdirs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +MODULE = ext-event-transport +CLASS = common +SRCS = fmevt_main.c fmevt_outbound.c + +include ../../Makefile.plugin + +CFLAGS += $(INCS) +LINTFLAGS += $(INCS) +LDLIBS += -lsysevent
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,52 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Configuration for the ext-event-transport transport module. This module +# forwards protocol events out of fmd for subscription by other entities +# using other libfmevent interfaces. +# + +# +# You can disable the forwarding functionality by setting this true +# +setprop protocol_forward_disable false + +# +# The channel we forward events on can be changed for simulation environments +# by changing the "outbound_channel" string property from its default. +# The maximum number of events that can queue in the channel (each +# consuming a little kernel memory) is controlled by "outbound_channel_depth". +# +# setprop outbound_channel ... +# setprop outbound_channel_depth 256 + +# +# Protocol event classes that will be forwarded. +# Changing this list may lead to breakage and/or excessive event forwarding. +# +subscribe list.* +subscribe swevent.* +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FMEVT_H +#define _FMEVT_H + +/* + * ext-event-transport module - implementation detail. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/fm/protocol.h> +#include <fm/fmd_api.h> +#include <fm/libfmevent.h> +#include <libnvpair.h> + +#include "../../../../../lib/fm/libfmevent/common/fmev_channels.h" + +extern fmd_hdl_t *fmevt_hdl; +extern const fmd_prop_t fmevt_props[]; + +extern void fmevt_init_outbound(fmd_hdl_t *); +extern void fmevt_fini_outbound(fmd_hdl_t *); + +extern void fmevt_recv(fmd_hdl_t *, fmd_event_t *, nvlist_t *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _FMEVT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/types.h> + +#include "fmevt.h" + +const fmd_prop_t fmevt_props[] = { + { "protocol_forward_disable", FMD_TYPE_BOOL, "false" }, + { "outbound_channel", FMD_TYPE_STRING, FMD_SNOOP_CHANNEL }, + { "outbound_channel_depth", FMD_TYPE_INT32, "256" }, + { NULL, 0, NULL }, +}; + +static const fmd_hdl_ops_t fmd_ops = { + fmevt_recv, /* fmdo_recv */ + NULL, /* fmdo_timeout */ + NULL, /* fmdo_close */ + NULL, /* fmdo_stats */ + NULL, /* fmdo_gc */ + NULL, /* fmdo_send */ + NULL /* fmdo_topo */ +}; + +static const fmd_hdl_info_t fmd_info = { + "External FM event transport", "0.1", &fmd_ops, fmevt_props +}; + +void +_fmd_init(fmd_hdl_t *hdl) +{ + /* + * Register the handle, pulling in configuration from our + * conf file. This includes our event class subscriptions + * for those events that we will forward out of fmd. + */ + if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) + return; + + fmevt_init_outbound(hdl); +} + +void +_fmd_fini(fmd_hdl_t *hdl) +{ + fmevt_fini_outbound(hdl); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,137 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/types.h> +#include <strings.h> +#include <fm/fmd_api.h> +#include <sys/fm/protocol.h> +#include <sys/fm/util.h> +#include <sys/sysevent.h> + +#include "fmevt.h" + +static evchan_t *fmevt_outbound_chan; + +static struct fmevt_outbound_stats { + fmd_stat_t recv_calls; + fmd_stat_t recv_list; + fmd_stat_t recv_swevent; + fmd_stat_t recv_other; + fmd_stat_t fwd_success; + fmd_stat_t fwd_failure; +} outbound_stats = { + { "outbound_recv_calls", FMD_TYPE_UINT64, + "total events received for forwarding" }, + { "outbound_cat1class_list", FMD_TYPE_UINT64, + "events received matching list.*" }, + { "outbound_cat1class_swevent", FMD_TYPE_UINT64, + "events received matching swevent.*" }, + { "outbound_cat1class_other", FMD_TYPE_UINT64, + "events of other classes" }, + { "outbound_fwd_success", FMD_TYPE_UINT64, + "events forwarded successfully" }, + { "outbound_fwd_failure", FMD_TYPE_UINT64, + "events we failed to forward" } +}; + +#define BUMPSTAT(stat) outbound_stats.stat.fmds_value.ui64++ + +/* + * In the .conf file we subscribe to list.* and swevent.* event classes. + * Any additions to that set could cause some unexpected behaviour. + * For example adding fault.foo won't work (since we don't publish + * faults directly but only within a list.suspect) but we will get + * any list.* including fault.foo as a suspect. + */ +/*ARGSUSED*/ +void +fmevt_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) +{ + BUMPSTAT(recv_calls); + + if (strncmp(class, "list.", 5) == 0) + BUMPSTAT(recv_list); + else if (strncmp(class, "swevent.", 8) == 0) + BUMPSTAT(recv_swevent); + else + BUMPSTAT(recv_other); + + if (sysevent_evc_publish(fmevt_outbound_chan, class, "", + SUNW_VENDOR, FM_PUB, nvl, EVCH_SLEEP) == 0) { + BUMPSTAT(fwd_success); + } else { + BUMPSTAT(fwd_failure); + fmd_hdl_debug(hdl, "sysevent_evc_publish failed:"); + } +} + +void +fmevt_init_outbound(fmd_hdl_t *hdl) +{ + int32_t channel_depth; + char *channel_name; + + if (fmd_prop_get_int32(hdl, "protocol_forward_disable") == B_TRUE) { + fmd_hdl_debug(hdl, "protocol forwarding disabled " + "through .conf file setting\n"); + return; + } + + (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (outbound_stats) / + sizeof (fmd_stat_t), (fmd_stat_t *)&outbound_stats); + + /* + * Allow simulation environment to change outbound channel name. + */ + channel_name = fmd_prop_get_string(hdl, "outbound_channel"); + + if (sysevent_evc_bind(channel_name, &fmevt_outbound_chan, + EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0) { + fmd_hdl_abort(hdl, "Unable to bind channel %s", + channel_name); + return; + } + + channel_depth = fmd_prop_get_int32(hdl, "outbound_channel_depth"); + + if (sysevent_evc_control(fmevt_outbound_chan, EVCH_SET_CHAN_LEN, + (uint32_t)channel_depth) != 0) { + fmd_hdl_abort(hdl, "Unable to set depth of channel %s to %d", + channel_name, channel_depth); + } + + fmd_prop_free_string(hdl, channel_name); +} + +/*ARGSUSED*/ +void +fmevt_fini_outbound(fmd_hdl_t *hdl) +{ + if (fmevt_outbound_chan != NULL) { + (void) sysevent_evc_unbind(fmevt_outbound_chan); + fmevt_outbound_chan = NULL; + } +}
--- a/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c Thu Nov 19 15:28:11 2009 +1100 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdlib.h> #include <unistd.h> #include <stdio.h> @@ -122,8 +120,8 @@ _fmd_fini(fmd_hdl_t *handle) { if (h_event != NULL) { - sysevent_evc_unsubscribe(h_event, SUBSCRIBE_ID); - sysevent_evc_unbind(h_event); + (void) sysevent_evc_unsubscribe(h_event, SUBSCRIBE_ID); + (void) sysevent_evc_unbind(h_event); } if (h_fmd != NULL && h_xprt != NULL)
--- a/usr/src/cmd/fps/fptest/fps_ereport_mod.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/cmd/fps/fptest/fps_ereport_mod.c Thu Nov 19 15:28:11 2009 +1100 @@ -197,7 +197,7 @@ (void) sleep(1); (void) fflush(NULL); - sysevent_evc_unbind(scp); + (void) sysevent_evc_unbind(scp); return (0); }
--- a/usr/src/head/door.h Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/head/door.h Thu Nov 19 15:28:11 2009 +1100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,16 +18,15 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DOOR_H #define _DOOR_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/door.h> #include <ucred.h> @@ -42,8 +40,11 @@ /* * Doors API */ -int door_create(void (*)(void *, char *, size_t, door_desc_t *, uint_t), - void *, uint_t); + +typedef void door_server_procedure_t(void *, char *, size_t, door_desc_t *, + uint_t); + +int door_create(door_server_procedure_t *, void *, uint_t); int door_revoke(int); int door_info(int, door_info_t *); int door_call(int, door_arg_t *); @@ -58,6 +59,14 @@ typedef void door_server_func_t(door_info_t *); door_server_func_t *door_server_create(door_server_func_t *); +typedef int door_xcreate_server_func_t(door_info_t *, + void *(*)(void *), void *, void *); +typedef void door_xcreate_thrsetup_func_t(void *); + +int door_xcreate(door_server_procedure_t *, void *, uint_t, + door_xcreate_server_func_t *, door_xcreate_thrsetup_func_t *, + void *, int); + #endif /* _ASM */ #ifdef __cplusplus
--- a/usr/src/lib/fm/Makefile Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/fm/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -20,28 +20,30 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../Makefile.lib +common_SUBDIRS = \ + libfmd_agent \ + libdiagcode \ + libdiskstatus \ + libfmd_adm \ + libfmd_log \ + libfmd_msg \ + libfmd_snmp \ + libfmevent \ + topo + sparc_SUBDIRS = \ libmdesc \ libldom i386_SUBDIRS = -SUBDIRS = \ - libfmd_agent \ - libdiagcode \ - libdiskstatus \ - libfmd_adm \ - libfmd_log \ - libfmd_msg \ - libfmd_snmp \ - $($(MACH)_SUBDIRS) \ - topo +SUBDIRS = $(common_SUBDIRS) $($(MACH)_SUBDIRS) libldom: libmdesc libfmd_agent
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,57 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../../Makefile.lib +include ../Makefile.lib + +FMHDRS = libfmevent.h +HDRDIR = common + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install +lint := TARGET = lint + +.KEEP_STATE: + +all clean clobber lint: $(SUBDIRS) + +install: install_h .WAIT $(SUBDIRS) + +install_h: $(ROOTFMHDRS) + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../../Makefile.targ +include ../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/Makefile.com Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,78 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +LIBRARY = libfmevent.a +VERS = .1 + +LIBSRCS = fmev_subscribe.c \ + fmev_evaccess.c \ + fmev_errstring.c \ + fmev_util.c + +OBJECTS = $(LIBSRCS:%.c=%.o) + +include ../../../Makefile.lib +include ../../Makefile.lib + +SRCS = $(LIBSRCS:%.c=../common/%.c) +LIBS = $(DYNLIB) $(LINTLIB) + +SRCDIR = ../common + +CPPFLAGS += -I../common -I. +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG + +CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS) +CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS) +LDLIBS += -lumem -lnvpair -luutil -lsysevent -lc + +LINTFLAGS = -msux +LINTFLAGS64 = -msux -m64 + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) +$(LINTLIB) := LINTFLAGS = -nsvx +$(LINTLIB) := LINTFLAGS64 = -nsvx -m64 + +CLEANFILES += ../common/fmev_errstring.c + +.KEEP_STATE: + +all: $(LIBS) + +lint: $(LINTLIB) lintcheck + +pics/%.o: ../$(MACH)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +../common/fmev_errstring.c: ../common/mkerror.sh ../common/libfmevent.h + sh ../common/mkerror.sh ../common/libfmevent.h > $@ + +%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +include ../../../Makefile.targ +include ../../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/amd64/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/fmev_channels.h Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FMEV_CHANNELS_H +#define _FMEV_CHANNELS_H + +/* + * libfmevent - private GPEC channel names + * + * Note: The contents of this file are private to the implementation of + * libfmevent and are subject to change at any time without notice. + * This file is not delivered into /usr/include. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define FMD_SNOOP_CHANNEL "com.sun:fm:protocol_snoop" + +#ifdef __cplusplus +} +#endif + +#endif /* _FMEV_CHANNELS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,277 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Subscription event access interfaces. + */ + +#include <sys/types.h> +#include <limits.h> +#include <atomic.h> +#include <libsysevent.h> +#include <umem.h> +#include <fm/libfmevent.h> +#include <sys/fm/protocol.h> + +#include "fmev_impl.h" + +#define API_ENTERV1(iep) \ + ((void) fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), \ + LIBFMEVENT_VERSION_1)) + +typedef struct { + uint32_t ei_magic; /* _FMEVMAGIC */ + volatile uint32_t ei_refcnt; /* reference count */ + fmev_shdl_t ei_hdl; /* handle received on */ + nvlist_t *ei_nvl; /* (duped) sysevent attribute list */ + uint64_t ei_fmtime[2]; /* embedded protocol event time */ +} fmev_impl_t; + +#define FMEV2IMPL(ev) ((fmev_impl_t *)(ev)) +#define IMPL2FMEV(iep) ((fmev_t)(iep)) + +#define _FMEVMAGIC 0x466d4576 /* "FmEv" */ + +#define EVENT_VALID(iep) ((iep)->ei_magic == _FMEVMAGIC && \ + (iep)->ei_refcnt > 0 && fmev_shdl_valid((iep)->ei_hdl)) + +#define FM_TIME_SEC 0 +#define FM_TIME_NSEC 1 + +/* + * Transform a received sysevent_t into an fmev_t. + */ + +uint64_t fmev_bad_attr, fmev_bad_tod, fmev_bad_class; + +fmev_t +fmev_sysev2fmev(fmev_shdl_t hdl, sysevent_t *sep, char **clsp, nvlist_t **nvlp) +{ + fmev_impl_t *iep; + uint64_t *tod; + uint_t nelem; + + if ((iep = fmev_shdl_alloc(hdl, sizeof (*iep))) == NULL) + return (NULL); + + /* + * sysevent_get_attr_list duplicates the nvlist - we free it + * in fmev_free when the reference count hits zero. + */ + if (sysevent_get_attr_list(sep, &iep->ei_nvl) != 0) { + fmev_shdl_free(hdl, iep, sizeof (*iep)); + fmev_bad_attr++; + return (NULL); + } + + *nvlp = iep->ei_nvl; + + if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, clsp) != 0) { + nvlist_free(iep->ei_nvl); + fmev_shdl_free(hdl, iep, sizeof (*iep)); + fmev_bad_class++; + return (NULL); + } + + if (nvlist_lookup_uint64_array(iep->ei_nvl, "__tod", &tod, + &nelem) != 0 || nelem != 2) { + nvlist_free(iep->ei_nvl); + fmev_shdl_free(hdl, iep, sizeof (*iep)); + fmev_bad_tod++; + return (NULL); + } + + iep->ei_fmtime[FM_TIME_SEC] = tod[0]; + iep->ei_fmtime[FM_TIME_NSEC] = tod[1]; + + /* + * Now remove the fmd-private __tod and __ttl members. + */ + (void) nvlist_remove_all(iep->ei_nvl, "__tod"); + (void) nvlist_remove_all(iep->ei_nvl, "__ttl"); + + iep->ei_magic = _FMEVMAGIC; + iep->ei_hdl = hdl; + iep->ei_refcnt = 1; + ASSERT(EVENT_VALID(iep)); + + return (IMPL2FMEV(iep)); +} + +static void +fmev_free(fmev_impl_t *iep) +{ + ASSERT(iep->ei_refcnt == 0); + + nvlist_free(iep->ei_nvl); + fmev_shdl_free(iep->ei_hdl, iep, sizeof (*iep)); +} + +void +fmev_hold(fmev_t ev) +{ + fmev_impl_t *iep = FMEV2IMPL(ev); + + ASSERT(EVENT_VALID(iep)); + + API_ENTERV1(iep); + + atomic_inc_32(&iep->ei_refcnt); +} + +void +fmev_rele(fmev_t ev) +{ + fmev_impl_t *iep = FMEV2IMPL(ev); + + ASSERT(EVENT_VALID(iep)); + + API_ENTERV1(iep); + + if (atomic_dec_32_nv(&iep->ei_refcnt) == 0) + fmev_free(iep); +} + +fmev_t +fmev_dup(fmev_t ev) +{ + fmev_impl_t *iep = FMEV2IMPL(ev); + fmev_impl_t *cp; + + ASSERT(EVENT_VALID(iep)); + + API_ENTERV1(iep); + + if (ev == NULL) { + (void) fmev_seterr(FMEVERR_API); + return (NULL); + } + + if ((cp = fmev_shdl_alloc(iep->ei_hdl, sizeof (*iep))) == NULL) { + (void) fmev_seterr(FMEVERR_ALLOC); + return (NULL); + } + + if (nvlist_dup(iep->ei_nvl, &cp->ei_nvl, 0) != 0) { + fmev_shdl_free(iep->ei_hdl, cp, sizeof (*cp)); + (void) fmev_seterr(FMEVERR_ALLOC); + return (NULL); + } + + cp->ei_magic = _FMEVMAGIC; + cp->ei_hdl = iep->ei_hdl; + cp->ei_refcnt = 1; + return (IMPL2FMEV(cp)); +} + +nvlist_t * +fmev_attr_list(fmev_t ev) +{ + fmev_impl_t *iep = FMEV2IMPL(ev); + + ASSERT(EVENT_VALID(iep)); + + API_ENTERV1(iep); + + if (ev == NULL) { + (void) fmev_seterr(FMEVERR_API); + return (NULL); + } else if (iep->ei_nvl == NULL) { + (void) fmev_seterr(FMEVERR_MALFORMED_EVENT); + return (NULL); + } + + return (iep->ei_nvl); +} + +const char * +fmev_class(fmev_t ev) +{ + fmev_impl_t *iep = FMEV2IMPL(ev); + const char *class; + + ASSERT(EVENT_VALID(iep)); + + API_ENTERV1(iep); + + if (ev == NULL) { + (void) fmev_seterr(FMEVERR_API); + return (""); + } + + if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, (char **)&class) != 0 || + *class == '\0') { + (void) fmev_seterr(FMEVERR_MALFORMED_EVENT); + return (""); + } + + return (class); +} + +fmev_err_t +fmev_timespec(fmev_t ev, struct timespec *tp) +{ + fmev_impl_t *iep = FMEV2IMPL(ev); + uint64_t timetlimit; + + ASSERT(EVENT_VALID(iep)); + API_ENTERV1(iep); + +#ifdef _LP64 + timetlimit = INT64_MAX; +#else + timetlimit = INT32_MAX; +#endif + + if (iep->ei_fmtime[FM_TIME_SEC] > timetlimit) + return (FMEVERR_OVERFLOW); + + tp->tv_sec = (time_t)iep->ei_fmtime[FM_TIME_SEC]; + tp->tv_nsec = (long)iep->ei_fmtime[FM_TIME_NSEC]; + + return (FMEV_SUCCESS); +} + +uint64_t +fmev_time_sec(fmev_t ev) +{ + return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_SEC]); +} + +uint64_t +fmev_time_nsec(fmev_t ev) +{ + return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_NSEC]); +} + +struct tm * +fmev_localtime(fmev_t ev, struct tm *tm) +{ + time_t seconds; + + seconds = (time_t)fmev_time_sec(ev); + return (localtime_r(&seconds, tm)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/fmev_impl.h Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,76 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FMEV_IMPL_H +#define _FMEV_IMPL_H + +/* + * libfmevent - private implementation + * + * Note: The contents of this file are private to the implementation of + * libfmevent and are subject to change at any time without notice. + * This file is not delivered into /usr/include. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <errno.h> +#include <libuutil.h> +#include <libsysevent.h> +#include <fm/libfmevent.h> + +#ifdef DEBUG +#define ASSERT(x) (assert(x)) +#else +#define ASSERT(x) +#endif + +struct fmev_hdl_cmn { + uint32_t hc_magic; + uint32_t hc_api_vers; + void *(*hc_alloc)(size_t); + void *(*hc_zalloc)(size_t); + void (*hc_free)(void *, size_t); +}; + +struct fmev_hdl_cmn *fmev_shdl_cmn(fmev_shdl_t); + +extern int fmev_api_init(struct fmev_hdl_cmn *); +extern int fmev_api_enter(struct fmev_hdl_cmn *, uint32_t); +extern void fmev_api_freetsd(void); +extern fmev_err_t fmev_seterr(fmev_err_t); +extern int fmev_shdl_valid(fmev_shdl_t); +extern fmev_t fmev_sysev2fmev(fmev_shdl_t, sysevent_t *sep, char **, + nvlist_t **); + +#ifdef __cplusplus +} +#endif + +#endif /* _FMEV_IMPL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,605 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * FMA event subscription interfaces - subscribe to FMA protocol + * from outside the fault manager. + */ + +#include <sys/types.h> +#include <atomic.h> +#include <libsysevent.h> +#include <libuutil.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <umem.h> +#include <unistd.h> + +#include <fm/libfmevent.h> + +#include "fmev_impl.h" +#include "fmev_channels.h" + +typedef struct { + struct fmev_hdl_cmn sh_cmn; + evchan_t *sh_binding; + uu_avl_pool_t *sh_pool; + uu_avl_t *sh_avl; + uint32_t sh_subcnt; + uint32_t sh_flags; + sysevent_subattr_t *sh_attr; + pthread_mutex_t sh_lock; + pthread_mutex_t sh_srlz_lock; +} fmev_shdl_impl_t; + +#define HDL2IHDL(hdl) ((fmev_shdl_impl_t *)(hdl)) +#define IHDL2HDL(ihdl) ((fmev_shdl_t)(ihdl)) + +#define _FMEV_SHMAGIC 0x5368446c /* ShDl */ +#define FMEV_SHDL_VALID(ihdl) ((ihdl)->sh_cmn.hc_magic == _FMEV_SHMAGIC) + +#define SHDL_FL_SERIALIZE 0x1 + +#define API_ENTERV1(hdl) \ + fmev_api_enter(&HDL2IHDL(hdl)->sh_cmn, LIBFMEVENT_VERSION_1) + +/* + * For each subscription on a handle we add a node to an avl tree + * to track subscriptions. + */ + +#define FMEV_SID_SZ (16 + 1) /* Matches MAX_SUBID_LEN */ + +struct fmev_subinfo { + uu_avl_node_t si_node; + fmev_shdl_impl_t *si_ihdl; + char si_pat[FMEV_MAX_CLASS]; + char si_sid[FMEV_SID_SZ]; + fmev_cbfunc_t *si_cb; + void *si_cbarg; +}; + +struct fmev_hdl_cmn * +fmev_shdl_cmn(fmev_shdl_t hdl) +{ + return (&HDL2IHDL(hdl)->sh_cmn); +} + +static int +shdlctl_start(fmev_shdl_impl_t *ihdl) +{ + (void) pthread_mutex_lock(&ihdl->sh_lock); + + if (ihdl->sh_subcnt == 0) { + return (1); /* lock still held */ + } else { + (void) pthread_mutex_unlock(&ihdl->sh_lock); + return (0); + } +} + +static void +shdlctl_end(fmev_shdl_impl_t *ihdl) +{ + (void) pthread_mutex_unlock(&ihdl->sh_lock); +} + +fmev_err_t +fmev_shdlctl_serialize(fmev_shdl_t hdl) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + if (!API_ENTERV1(hdl)) + return (fmev_errno); + + if (!shdlctl_start(ihdl)) + return (fmev_seterr(FMEVERR_BUSY)); + + if (!(ihdl->sh_flags & SHDL_FL_SERIALIZE)) { + (void) pthread_mutex_init(&ihdl->sh_srlz_lock, NULL); + ihdl->sh_flags |= SHDL_FL_SERIALIZE; + } + + shdlctl_end(ihdl); + return (fmev_seterr(FMEV_SUCCESS)); +} + +fmev_err_t +fmev_shdlctl_thrattr(fmev_shdl_t hdl, pthread_attr_t *attr) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + if (!API_ENTERV1(hdl)) + return (fmev_errno); + + if (!shdlctl_start(ihdl)) + return (fmev_seterr(FMEVERR_BUSY)); + + sysevent_subattr_thrattr(ihdl->sh_attr, attr); + + shdlctl_end(ihdl); + return (fmev_seterr(FMEV_SUCCESS)); +} + +fmev_err_t +fmev_shdlctl_sigmask(fmev_shdl_t hdl, sigset_t *set) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + if (!API_ENTERV1(hdl)) + return (fmev_errno); + + if (!shdlctl_start(ihdl)) + return (fmev_seterr(FMEVERR_BUSY)); + + sysevent_subattr_sigmask(ihdl->sh_attr, set); + + shdlctl_end(ihdl); + return (fmev_seterr(FMEV_SUCCESS)); +} + +fmev_err_t +fmev_shdlctl_thrsetup(fmev_shdl_t hdl, door_xcreate_thrsetup_func_t *func, + void *cookie) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + if (!API_ENTERV1(hdl)) + return (fmev_errno); + + if (!shdlctl_start(ihdl)) + return (fmev_seterr(FMEVERR_BUSY)); + + sysevent_subattr_thrsetup(ihdl->sh_attr, func, cookie); + + shdlctl_end(ihdl); + return (fmev_seterr(FMEV_SUCCESS)); +} + +fmev_err_t +fmev_shdlctl_thrcreate(fmev_shdl_t hdl, door_xcreate_server_func_t *func, + void *cookie) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + if (!API_ENTERV1(hdl)) + return (fmev_errno); + + if (!shdlctl_start(ihdl)) + return (fmev_seterr(FMEVERR_BUSY)); + + sysevent_subattr_thrcreate(ihdl->sh_attr, func, cookie); + + shdlctl_end(ihdl); + return (fmev_seterr(FMEV_SUCCESS)); +} + +/* + * Our door service function. We return 0 regardless so that the kernel + * does not keep either retrying (EAGAIN) or bleat to cmn_err. + */ + +uint64_t fmev_proxy_cb_inval; +uint64_t fmev_proxy_cb_enomem; + +int +fmev_proxy_cb(sysevent_t *sep, void *arg) +{ + struct fmev_subinfo *sip = arg; + fmev_shdl_impl_t *ihdl = sip->si_ihdl; + nvlist_t *nvl; + char *class; + fmev_t ev; + + if (sip == NULL || sip->si_cb == NULL) { + fmev_proxy_cb_inval++; + return (0); + } + + if ((ev = fmev_sysev2fmev(IHDL2HDL(ihdl), sep, &class, &nvl)) == NULL) { + fmev_proxy_cb_enomem++; + return (0); + } + + if (ihdl->sh_flags & SHDL_FL_SERIALIZE) + (void) pthread_mutex_lock(&ihdl->sh_srlz_lock); + + sip->si_cb(ev, class, nvl, sip->si_cbarg); + + if (ihdl->sh_flags & SHDL_FL_SERIALIZE) + (void) pthread_mutex_unlock(&ihdl->sh_srlz_lock); + + fmev_rele(ev); /* release hold obtained in fmev_sysev2fmev */ + + return (0); +} + +static volatile uint32_t fmev_subid; + +fmev_err_t +fmev_shdl_subscribe(fmev_shdl_t hdl, const char *pat, fmev_cbfunc_t func, + void *funcarg) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + struct fmev_subinfo *sip; + uu_avl_index_t idx; + uint64_t nsid; + int serr; + + if (!API_ENTERV1(hdl)) + return (fmev_errno); + + if (pat == NULL || func == NULL) + return (fmev_seterr(FMEVERR_API)); + + /* + * Empty class patterns are illegal, as is the sysevent magic for + * all classes. Also validate class length. + */ + if (*pat == '\0' || strncmp(pat, EC_ALL, sizeof (EC_ALL)) == 0 || + strncmp(pat, EC_SUB_ALL, sizeof (EC_SUB_ALL)) == 0 || + strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS) + return (fmev_seterr(FMEVERR_BADCLASS)); + + if ((sip = fmev_shdl_zalloc(hdl, sizeof (*sip))) == NULL) + return (fmev_seterr(FMEVERR_ALLOC)); + + (void) strncpy(sip->si_pat, pat, sizeof (sip->si_pat)); + + uu_avl_node_init(sip, &sip->si_node, ihdl->sh_pool); + + (void) pthread_mutex_lock(&ihdl->sh_lock); + + if (uu_avl_find(ihdl->sh_avl, sip, NULL, &idx) != NULL) { + (void) pthread_mutex_unlock(&ihdl->sh_lock); + fmev_shdl_free(hdl, sip, sizeof (*sip)); + return (fmev_seterr(FMEVERR_DUPLICATE)); + } + + /* + * Generate a subscriber id for GPEC that is unique to this + * subscription. There is no provision for persistent + * subscribers. The subscriber id must be unique within + * this zone. + */ + nsid = (uint64_t)getpid() << 32 | atomic_inc_32_nv(&fmev_subid); + (void) snprintf(sip->si_sid, sizeof (sip->si_sid), "%llx", nsid); + + sip->si_ihdl = ihdl; + sip->si_cb = func; + sip->si_cbarg = funcarg; + + if ((serr = sysevent_evc_xsubscribe(ihdl->sh_binding, sip->si_sid, + sip->si_pat, fmev_proxy_cb, sip, 0, ihdl->sh_attr)) != 0) { + fmev_err_t err; + + (void) pthread_mutex_unlock(&ihdl->sh_lock); + fmev_shdl_free(hdl, sip, sizeof (*sip)); + + switch (serr) { + case ENOMEM: + err = FMEVERR_MAX_SUBSCRIBERS; + break; + + default: + err = FMEVERR_INTERNAL; + break; + } + + return (fmev_seterr(err)); + } + + uu_avl_insert(ihdl->sh_avl, sip, idx); + ihdl->sh_subcnt++; + + (void) pthread_mutex_unlock(&ihdl->sh_lock); + + return (fmev_seterr(FMEV_SUCCESS)); +} + +static int +fmev_subinfo_fini(fmev_shdl_impl_t *ihdl, struct fmev_subinfo *sip, + boolean_t doavl) +{ + int err; + + ASSERT(sip->si_ihdl == ihdl); + + err = sysevent_evc_unsubscribe(ihdl->sh_binding, sip->si_sid); + + if (err == 0) { + if (doavl) { + uu_avl_remove(ihdl->sh_avl, sip); + uu_avl_node_fini(sip, &sip->si_node, ihdl->sh_pool); + } + fmev_shdl_free(IHDL2HDL(ihdl), sip, sizeof (*sip)); + ihdl->sh_subcnt--; + } + + return (err); +} + +fmev_err_t +fmev_shdl_unsubscribe(fmev_shdl_t hdl, const char *pat) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + fmev_err_t rv = FMEVERR_NOMATCH; + struct fmev_subinfo *sip; + struct fmev_subinfo si; + int err; + + if (!API_ENTERV1(hdl)) + return (fmev_errno); + + if (pat == NULL) + return (fmev_seterr(FMEVERR_API)); + + if (*pat == '\0' || strncmp(pat, EVCH_ALLSUB, sizeof (EC_ALL)) == 0 || + strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS) + return (fmev_seterr(FMEVERR_BADCLASS)); + + (void) strncpy(si.si_pat, pat, sizeof (si.si_pat)); + + (void) pthread_mutex_lock(&ihdl->sh_lock); + + if ((sip = uu_avl_find(ihdl->sh_avl, &si, NULL, NULL)) != NULL) { + if ((err = fmev_subinfo_fini(ihdl, sip, B_TRUE)) == 0) { + rv = FMEV_SUCCESS; + } else { + /* + * Return an API error if the unsubscribe was + * attempted from within a door callback invocation; + * other errors should not happen. + */ + rv = (err == EDEADLK) ? FMEVERR_API : FMEVERR_INTERNAL; + } + } + + (void) pthread_mutex_unlock(&ihdl->sh_lock); + + return (fmev_seterr(rv)); +} + +static void * +dflt_alloc(size_t sz) +{ + return (umem_alloc(sz, UMEM_DEFAULT)); +} + +static void * +dflt_zalloc(size_t sz) +{ + return (umem_zalloc(sz, UMEM_DEFAULT)); +} + +static void +dflt_free(void *buf, size_t sz) +{ + umem_free(buf, sz); +} + +void * +fmev_shdl_alloc(fmev_shdl_t hdl, size_t sz) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + (void) API_ENTERV1(hdl); + + return (ihdl->sh_cmn.hc_alloc(sz)); +} + +void * +fmev_shdl_zalloc(fmev_shdl_t hdl, size_t sz) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + (void) API_ENTERV1(hdl); + + return (ihdl->sh_cmn.hc_zalloc(sz)); +} + +void +fmev_shdl_free(fmev_shdl_t hdl, void *buf, size_t sz) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + (void) API_ENTERV1(hdl); + + ihdl->sh_cmn.hc_free(buf, sz); +} + +int +fmev_shdl_valid(fmev_shdl_t hdl) +{ + return (FMEV_SHDL_VALID(HDL2IHDL(hdl))); +} + +/*ARGSUSED*/ +static int +fmev_keycmp(const void *l, const void *r, void *arg) +{ + struct fmev_subinfo *left = (struct fmev_subinfo *)l; + struct fmev_subinfo *right = (struct fmev_subinfo *)r; + + return (strncmp(left->si_pat, right->si_pat, FMEV_MAX_CLASS)); +} + +fmev_shdl_t +fmev_shdl_init(uint32_t caller_version, void *(*hdlalloc)(size_t), + void *(*hdlzalloc)(size_t), void (*hdlfree)(void *, size_t)) +{ + fmev_shdl_impl_t *ihdl; + struct fmev_hdl_cmn hc; + const char *chan_name; + int err; + + hc.hc_magic = _FMEV_SHMAGIC; + hc.hc_api_vers = caller_version; + hc.hc_alloc = hdlalloc ? hdlalloc : dflt_alloc; + hc.hc_zalloc = hdlzalloc ? hdlzalloc : dflt_zalloc; + hc.hc_free = hdlfree ? hdlfree : dflt_free; + + if (!fmev_api_init(&hc)) + return (NULL); /* error type set */ + + if (!((hdlalloc == NULL && hdlzalloc == NULL && hdlfree == NULL) || + (hdlalloc != NULL && hdlzalloc != NULL && hdlfree != NULL))) { + (void) fmev_seterr(FMEVERR_API); + return (NULL); + } + + if (hdlzalloc == NULL) + ihdl = dflt_zalloc(sizeof (*ihdl)); + else + ihdl = hdlzalloc(sizeof (*ihdl)); + + if (ihdl == NULL) { + (void) fmev_seterr(FMEVERR_ALLOC); + return (NULL); + } + + ihdl->sh_cmn = hc; + + if ((ihdl->sh_attr = sysevent_subattr_alloc()) == NULL) { + err = FMEVERR_ALLOC; + goto error; + } + + (void) pthread_mutex_init(&ihdl->sh_lock, NULL); + + /* + * For simulation purposes we allow an environment variable + * to provide a different channel name. + */ + if ((chan_name = getenv("FMD_SNOOP_CHANNEL")) == NULL) + chan_name = FMD_SNOOP_CHANNEL; + + /* + * Try to bind to the event channel. If it's not already present, + * attempt to create the channel so that we can startup before + * the event producer (who will also apply choices such as + * channel depth when they bind to the channel). + */ + if (sysevent_evc_bind(chan_name, &ihdl->sh_binding, + EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0) { + switch (errno) { + case EINVAL: + default: + err = FMEVERR_INTERNAL; + break; + case ENOMEM: + err = FMEVERR_ALLOC; + break; + case EPERM: + err = FMEVERR_NOPRIV; + break; + } + goto error; + } + + if ((ihdl->sh_pool = uu_avl_pool_create("subinfo_pool", + sizeof (struct fmev_subinfo), + offsetof(struct fmev_subinfo, si_node), fmev_keycmp, + UU_AVL_POOL_DEBUG)) == NULL) { + err = FMEVERR_INTERNAL; + goto error; + } + + if ((ihdl->sh_avl = uu_avl_create(ihdl->sh_pool, NULL, + UU_DEFAULT)) == NULL) { + err = FMEVERR_INTERNAL; + goto error; + } + + return (IHDL2HDL(ihdl)); + +error: + (void) fmev_shdl_fini(IHDL2HDL(ihdl)); + (void) fmev_seterr(err); + return (NULL); +} + +fmev_err_t +fmev_shdl_fini(fmev_shdl_t hdl) +{ + fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl); + + (void) API_ENTERV1(hdl); + + (void) pthread_mutex_lock(&ihdl->sh_lock); + + /* + * Verify that we are not in callback context - return an API + * error if we are. + */ + if (sysevent_evc_unsubscribe(ihdl->sh_binding, "invalidsid") == + EDEADLK) { + (void) pthread_mutex_unlock(&ihdl->sh_lock); + return (fmev_seterr(FMEVERR_API)); + } + + if (ihdl->sh_avl) { + void *cookie = NULL; + struct fmev_subinfo *sip; + + while ((sip = uu_avl_teardown(ihdl->sh_avl, &cookie)) != NULL) + (void) fmev_subinfo_fini(ihdl, sip, B_FALSE); + + uu_avl_destroy(ihdl->sh_avl); + ihdl->sh_avl = NULL; + } + + ASSERT(ihdl->sh_subcnt == 0); + + if (ihdl->sh_binding) { + (void) sysevent_evc_unbind(ihdl->sh_binding); + ihdl->sh_binding = NULL; + } + + if (ihdl->sh_pool) { + uu_avl_pool_destroy(ihdl->sh_pool); + ihdl->sh_pool = NULL; + } + + if (ihdl->sh_attr) { + sysevent_subattr_free(ihdl->sh_attr); + ihdl->sh_attr = NULL; + } + + ihdl->sh_cmn.hc_magic = 0; + + (void) pthread_mutex_unlock(&ihdl->sh_lock); + (void) pthread_mutex_destroy(&ihdl->sh_lock); + + fmev_shdl_free(hdl, hdl, sizeof (*ihdl)); + + fmev_api_freetsd(); + + return (fmev_seterr(FMEV_SUCCESS)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/fmev_util.c Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,180 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Subscription event access interfaces. + */ + +#include <sys/types.h> +#include <pthread.h> +#include <umem.h> +#include <fm/libfmevent.h> + +#include "fmev_impl.h" + +static pthread_key_t fmev_tsdkey = PTHREAD_ONCE_KEY_NP; +static int key_inited; + +/* + * Thread and handle specific data. + */ +struct fmev_tsd { + fmev_err_t ts_lasterr; +}; + +static void +fmev_tsd_destructor(void *data) +{ + umem_free(data, sizeof (struct fmev_tsd)); +} + +/* + * Called only from fmev_shdl_init. Check we are opening a valid version + * of the ABI. + */ +int +fmev_api_init(struct fmev_hdl_cmn *hc) +{ + if (!fmev_api_enter(NULL, 0)) + return (0); + /* + * We implement only version 1 of the ABI at this point. + */ + if (hc->hc_api_vers != LIBFMEVENT_VERSION_1) { + if (key_inited) + (void) fmev_seterr(FMEVERR_VERSION_MISMATCH); + return (0); + } + + return (1); +} + +/* + * On entry to other libfmevent API members we call fmev_api_enter. + * Some thread-specific data is used to keep a per-thread error value. + * The version opened must be no greater than the latest version but can + * be older. The ver_intro is the api version at which the interface + * was added - the caller must have opened at least this version. + */ +int +fmev_api_enter(struct fmev_hdl_cmn *hc, uint32_t ver_intro) +{ + struct fmev_tsd *tsd; + + /* Initialize key on first visit */ + if (!key_inited) { + (void) pthread_key_create_once_np(&fmev_tsdkey, + fmev_tsd_destructor); + key_inited = 1; + } + + /* + * Allocate TSD for error value for this thread. It is only + * freed if/when the thread exits. + */ + if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL) { + if ((tsd = umem_alloc(sizeof (*tsd), UMEM_DEFAULT)) == NULL || + pthread_setspecific(fmev_tsdkey, (const void *)tsd) != 0) { + if (tsd) + umem_free(tsd, sizeof (*tsd)); + return (0); /* no error set, but what can we do */ + } + } + + tsd->ts_lasterr = 0; + + if (hc == NULL) { + return (1); + } + + /* Enforce version adherence. */ + if (ver_intro > hc->hc_api_vers || + hc->hc_api_vers > LIBFMEVENT_VERSION_LATEST || + ver_intro > LIBFMEVENT_VERSION_LATEST) { + tsd->ts_lasterr = FMEVERR_VERSION_MISMATCH; + return (0); + } + + return (1); +} + +/* + * Called on any fmev_shdl_fini. Free the TSD for this thread. If this + * thread makes other API calls for other open handles, or opens a new + * handle, then TSD will be allocated again in fmev_api_enter. + */ +void +fmev_api_freetsd(void) +{ + struct fmev_tsd *tsd; + + if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL) { + (void) pthread_setspecific(fmev_tsdkey, NULL); + fmev_tsd_destructor((void *)tsd); + } +} + +/* + * To return an error condition an API member first sets the error type + * with a call to fmev_seterr and then returns NULL or whatever it wants. + * The caller can then retrieve the per-thread error type using fmev_errno + * or format it with fmev_strerr. + */ +fmev_err_t +fmev_seterr(fmev_err_t error) +{ + struct fmev_tsd *tsd; + + ASSERT(key_inited); + + if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL) + tsd->ts_lasterr = error; + + return (error); +} + +/* + * fmev_errno is a macro defined in terms of the following function. It + * can be used to dereference the last error value on the current thread; + * it must not be used to assign to fmev_errno. + */ + +const fmev_err_t apierr = FMEVERR_API; +const fmev_err_t unknownerr = FMEVERR_UNKNOWN; + +const fmev_err_t * +__fmev_errno(void) +{ + struct fmev_tsd *tsd; + + if (!key_inited) + return (&apierr); + + if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL) + return (&unknownerr); + + return ((const fmev_err_t *)&tsd->ts_lasterr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/libfmevent.h Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,279 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBFMEVENT_H +#define _LIBFMEVENT_H + +/* + * FMA event library. + * + * A. Protocol event subscription interfaces (Committed). + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <libnvpair.h> +#include <stdlib.h> +#include <door.h> +#include <sys/time.h> +#include <sys/fm/protocol.h> + +/* + * Library ABI interface version. Quote the version you are using + * to fmev_shdl_init. Only interfaces introduced in or prior to the + * quoted version will be available. Once introduced an interface + * only ever changes compatibly. + */ +#define LIBFMEVENT_VERSION_1 1 + +#define LIBFMEVENT_VERSION_LATEST LIBFMEVENT_VERSION_1 + +/* + * Success and error return values. The descriptive comment for each + * FMEVERR_* becomes the string that is returned by fmev_strerror for that + * error type. + */ +typedef enum { + FMEV_SUCCESS = 0, + FMEV_OK = FMEV_SUCCESS, /* alias for FMEV_SUCCESS */ + FMEVERR_UNKNOWN = 0xe000, /* Error details unknown */ + FMEVERR_VERSION_MISMATCH, /* Library ABI version incompatible with caller */ + FMEVERR_API, /* Library API usage violation */ + FMEVERR_ALLOC, /* Failed to allocate additional resources */ + FMEVERR_MALFORMED_EVENT, /* Event contents are inconsistent or corrupt */ + FMEVERR_OVERFLOW, /* Operation would overflow result type */ + FMEVERR_INTERNAL, /* Internal library error */ + FMEVERR_NOPRIV, /* Insufficient permissions or privilege */ + FMEVERR_BUSY, /* Resource is busy */ + FMEVERR_DUPLICATE, /* Duplicate request */ + FMEVERR_BADCLASS, /* Bad event class or class pattern */ + FMEVERR_NOMATCH, /* No match to criteria provided */ + FMEVERR_MAX_SUBSCRIBERS, /* Exceeds maximum subscribers per handle */ + FMEVERR_INVALIDARG /* Argument is invalid */ +} fmev_err_t; + +/* + * Some interfaces return an fmev_err_t - FMEV_SUCCESS on success, otherwise + * failure of the indicated type. You can use fmev_strerror to render an + * fmev_err_t into a string. + * + * Other interfaces do not return an fmev_err_t directly. For example + * where we return a pointer an error is indicated by a NULL return. + * In these cases you can retrieve the fmev_err_t describing the reason + * for the failure using fmev_errno or get a string with + * fmev_strerr(fmev_errno). Note that fmev_errno is per-thread and holds + * the error value for any error that occured during the last libfmevent + * API call made by the current thread. Use fmev_errno as you would + * regular errno, but you should not assign to fmev_errno. + */ +extern const fmev_err_t *__fmev_errno(void); /* do not use this directly */ +#define fmev_errno (*(__fmev_errno())) +extern const char *fmev_strerror(fmev_err_t); + +/* + * Part A - Protocol Event Subscription + * ====== + * + * Subscribe to FMA protocol events published by the fault management + * daemon, receiving a callback for each matching event. + * + * This is a Committed interface (see attributes(5) for a definition). + */ + +/* + * Opaque subscription handle and event types. + */ +typedef struct fmev_shdl *fmev_shdl_t; +typedef struct fmev *fmev_t; + +/* + * Subscription callback function type for fmev_shdl_subscribe. + */ +typedef void fmev_cbfunc_t(fmev_t, const char *, nvlist_t *, void *); + +/* + * Initialize a new handle using fmev_shdl_init and quoting interface + * version number along with alloc, zalloc and free function pointers (all + * NULL to use the defaults. + * + * Close the handle and release resources with fmev_shdl_fini. + */ + +extern fmev_shdl_t fmev_shdl_init(uint32_t, + void *(*)(size_t), /* alloc */ + void *(*)(size_t), /* zalloc */ + void (*)(void *, size_t)); /* free */ + +extern fmev_err_t fmev_shdl_fini(fmev_shdl_t); + +/* + * Having created a handle you may optionally configure various properties + * for this handle using fmev_shdlctl_*. In most cases accepting the defaults + * (that are obtained through fmev_shdl_init alone) will provide adequate + * semantics - the controls below are provided for applications + * that require fine-grained control over event delivery semantics and, in + * particular, the service threads used to perform delivery callbacks. + * + * These controls may only be applied to a subscription handle + * that has no current subscriptions in place. You therefore cannot + * change the properties once subscriptions are established, and the + * handle properties apply uniformly to all subscriptions on that handle. + * If you require different properties per subscription then use multiple + * handles. + * + * fmev_shdlctl_serialize() will serialize all callbacks arising from all + * subscriptions on a handle. Event deliveries are normally single-threaded + * on a per-subscribtion bases, that is a call to fmev_shdl_subscribe + * will have deliveries arising from that subscription delivered + * in a serialized fashion on a single thread dedicated to the subscription. + * If multiple subscriptions are established then each has a dedicated + * delivery thread - fmev_shdlctl_serialize arranges that only one of these + * threads services a callback at any one time. + * + * fmev_shdlctl_thrattr() allows you to provide thread attributes for use + * in pthread_create() when server threads are created. The attributes + * are not copied - the pthread_attr_t object passed must exist for + * the duration of all subscriptions on the handle. These attributes only + * apply if fmev_shdlctl_thrcreate() is not in use on this handle. + * + * fmev_shdlctl_sigmask() allows you to provide a sigset_t signal mask + * of signals to block in server threads. The pthread_sigmask is set + * to this immediately before pthread_create, and restored immediately + * after pthread_create. This mask only applies if fmev_shdlctl_thrcreate() + * is not in use on this handle. + * + * fmev_shdlctl_thrsetup() allows you to install a custom door server thread + * setup function - see door_xcreate(3C). This will be used with the + * default thread creation semantics or with any custom thread creation + * function appointed with fmev_shdlctl_thrcreate(). + * + * fmev_shdlctl_thrcreate() allows you to install a custom door server thread + * creation function - see door_xcreate(3C). This option excludes + * fmev_shdlctl_{thrattr,sigmask} but the remaining options + * of fmev_shdlctl_{serialize,thrsetup} are still available. + */ + +extern fmev_err_t fmev_shdlctl_serialize(fmev_shdl_t); +extern fmev_err_t fmev_shdlctl_thrattr(fmev_shdl_t, pthread_attr_t *); +extern fmev_err_t fmev_shdlctl_sigmask(fmev_shdl_t, sigset_t *); +extern fmev_err_t fmev_shdlctl_thrsetup(fmev_shdl_t, + door_xcreate_thrsetup_func_t *, void *); +extern fmev_err_t fmev_shdlctl_thrcreate(fmev_shdl_t, + door_xcreate_server_func_t *, void *); + +/* + * Specify subscription choices on a handle using fmev_shdl_subscribe as + * many times as needed to describe the full event set. The event class + * pattern can be wildcarded using simple '*' wildcarding. When an event + * matching a subscription is received a callback is performed to the + * nominated function passing a fmev_t handle on the event and the + * requested cookie argument. + * + * See the fault management event protocol specification for a description + * of event classes. + * + * Drop a subscription using fmev_shdl_unsubscribe (which must match an + * earlier subscription). + */ + +#define FMEV_MAX_CLASS 64 /* Longest class string for subscription */ + +extern fmev_err_t fmev_shdl_subscribe(fmev_shdl_t, const char *, fmev_cbfunc_t, + void *); +extern fmev_err_t fmev_shdl_unsubscribe(fmev_shdl_t, const char *); + +/* + * Event access. In the common case that the event is processed to + * completion in the context of the event callback you need only + * use fmev_attr_list to access the nvlist of event attributes, + * with no responsibility for freeing the event or the nvlist; for + * convenience, fmev_class and fmev_timestamp can both be used to + * look inside an event without having to work with the attribute list (and + * the callback receives the class as an argument). + * + * See libnvpair(3LIB) for interfaces to access an nvlist_t. + * + * The remaining interfaces apply in the case that event handling will + * continue beyond the context of the event callback in which it is received. + * + * The fmev_t handle received in a callback is reference-counted; + * the initial reference count on entry to the callback is 1, and the + * count is always decremented when the callback completes. To continue + * to operate on a received event outside of the context of the callback + * in which it is first received, take an fmev_hold during the callback + * and later fmev_rele to release your hold (and free the event if the count + * drops to 0). + * + * To access attributes of an event use fmev_attr_list to receive + * an nvlist_t pointer valid for the same lifetime as the event itself (i.e., + * until its reference count drops to zero). + * + * If changes are made to a received fmev_t (discouraged) then all who + * have a hold on the event share the change. To obtain an independent + * copy of an fmev_t, with a reference count of 1, use fmev_dup. When + * finished with the copy decrement the reference count + * using fmev_rele - the event will be freed if the count reaches 0. + * + * For convenience you can retrieve the class of an event using fmev_class + * (it's also available as an argument to a callback, and within the + * event attribute list). The string returned by fmev_class is valid for + * the same lifetime as the event itself. + * + * The time at which a protocol event was generated is available via + * fmev_timespec; tv_sec has seconds since the epoch, and tv_nsec nanoseconds + * past that second. This can fail with FMEVERR_OVERFLOW if the seconds + * value does not fit within a time_t; you can retrieve the 64-bit second + * and nanosecond values with fmev_time_sec and fmev_time_nsec. + */ + +extern nvlist_t *fmev_attr_list(fmev_t); +extern const char *fmev_class(fmev_t); + +extern fmev_err_t fmev_timespec(fmev_t, struct timespec *); +extern uint64_t fmev_time_sec(fmev_t); +extern uint64_t fmev_time_nsec(fmev_t); +extern struct tm *fmev_localtime(fmev_t, struct tm *); + +extern void fmev_hold(fmev_t); +extern void fmev_rele(fmev_t); +extern fmev_t fmev_dup(fmev_t); + +/* + * The following will allocate and free memory based on the choices made + * at fmev_shdl_init. + */ +void *fmev_shdl_alloc(fmev_shdl_t, size_t); +void *fmev_shdl_zalloc(fmev_shdl_t, size_t); +void fmev_shdl_free(fmev_shdl_t, void *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBFMEVENT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/llib-lfmevent Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,30 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <fm/libfmevent.h>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/mapfile-vers Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,73 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +SUNW_1.1 { + global: + fmev_attr_list; + fmev_class; + fmev_dup; + fmev_hold; + fmev_localtime; + fmev_rele; + fmev_shdl_alloc; + fmev_shdl_init; + fmev_shdl_fini; + fmev_shdl_free; + fmev_shdl_subscribe; + fmev_shdl_unsubscribe; + fmev_shdl_zalloc; + fmev_shdlctl_serialize; + fmev_shdlctl_sigmask; + fmev_shdlctl_thrattr; + fmev_shdlctl_thrcreate; + fmev_shdlctl_thrsetup; + fmev_strerror; + fmev_timespec; + fmev_time_nsec; + fmev_time_sec; + local: + *; +}; + +SUNWprivate { + global: + __fmev_errno; + local: + *; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/common/mkerror.sh Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,65 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +cat <<EOM +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This file was generated during make. + */ + +#include <fm/libfmevent.h> + +static const char *_fmev_errstrs[] = { +EOM + +pattern='^ \(FMEVERR_[A-Z0-9_]*\).*\/\* *\(.*\) *\*\/.*' +replace=' "\2" \/\* \1 \*\/,' + +sed -n "s/$pattern/$replace/p" $1 || exit 1 + +cat <<EOM +}; + +static const int _fmev_nerrs = + sizeof (_fmev_errstrs) / sizeof (_fmev_errstrs[0]); + +const char * +fmev_strerror(fmev_err_t err) +{ + const char *s; + + if (err >= FMEVERR_UNKNOWN && (err - FMEVERR_UNKNOWN < _fmev_nerrs)) + s = _fmev_errstrs[err - FMEVERR_UNKNOWN]; + else + s = _fmev_errstrs[0]; + + return (s); +} +EOM
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/i386/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,28 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/sparc/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,28 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/libfmevent/sparcv9/Makefile Thu Nov 19 15:28:11 2009 +1100 @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- a/usr/src/lib/libc/amd64/sys/door.s Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libc/amd64/sys/door.s Thu Nov 19 15:28:11 2009 +1100 @@ -37,7 +37,6 @@ ANSI_PRAGMA_WEAK2(door_info,__door_info,function) ANSI_PRAGMA_WEAK2(door_revoke,__door_revoke,function) ANSI_PRAGMA_WEAK2(door_setparam,__door_setparam,function) - ANSI_PRAGMA_WEAK2(door_unbind,__door_unbind,function) /* * Offsets within struct door_results @@ -110,10 +109,8 @@ /* * this is the last server thread - call creation func for more */ - movq _daref_(door_server_func), %rax - movq 0(%rax), %rax movq DOOR_INFO_PTR(%rsp), %rdi - call *%rax /* call create function */ + call door_depletion_cb@PLT 1: /* Call the door server function now */ movq DOOR_COOKIE(%rsp), %rdi
--- a/usr/src/lib/libc/i386/sys/door.s Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libc/i386/sys/door.s Thu Nov 19 15:28:11 2009 +1100 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,7 +37,6 @@ ANSI_PRAGMA_WEAK2(door_info,__door_info,function) ANSI_PRAGMA_WEAK2(door_revoke,__door_revoke,function) ANSI_PRAGMA_WEAK2(door_setparam,__door_setparam,function) - ANSI_PRAGMA_WEAK2(door_unbind,__door_unbind,function) /* * Offsets within struct door_results @@ -153,13 +152,9 @@ * this is the last server thread - call creation func for more */ movl DOOR_INFO_PTR(%esp), %eax - _prologue_ pushl %eax /* door_info_t * */ - movl _daref_(door_server_func), %eax - movl 0(%eax), %eax - call *%eax /* call create function */ + call door_depletion_cb@PLT addl $4, %esp - _epilogue_ 1: /* Call the door server function now */ movl DOOR_PC(%esp), %eax @@ -192,7 +187,6 @@ cmpl %eax, %edx /* same process? */ movl $EINTR, %eax /* if no, return EINTR (child of forkall) */ jne 4f - movl $0, 4(%esp) /* clear arguments and restart */ movl $0, 8(%esp) movl $0, 12(%esp)
--- a/usr/src/lib/libc/port/mapfile-vers Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libc/port/mapfile-vers Thu Nov 19 15:28:11 2009 +1100 @@ -100,6 +100,7 @@ door_setparam; door_ucred; door_unbind; + door_xcreate; err; errx; faccessat;
--- a/usr/src/lib/libc/port/threads/door_calls.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libc/port/threads/door_calls.c Thu Nov 19 15:28:11 2009 +1100 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "lint.h" #include "thr_uberdata.h" #include "libc.h" @@ -39,7 +37,10 @@ #include <door.h> #include <signal.h> #include <ucred.h> +#include <strings.h> +#include <ucontext.h> #include <sys/ucred.h> +#include <atomic.h> static door_server_func_t door_create_server; @@ -62,6 +63,61 @@ size_t); extern int __door_ucred(ucred_t *); extern int __door_unref(void); +extern int __door_unbind(void); + +/* + * Key for per-door data for doors created with door_xcreate. + */ +static pthread_key_t privdoor_key = PTHREAD_ONCE_KEY_NP; + +/* + * Each door_xcreate'd door has a struct privdoor_data allocated for it, + * and each of the initial pool of service threads for the door + * has TSD for the privdoor_key set to point to this structure. + * When a thread in door_return decides it is time to perform a + * thread depletion callback we can retrieve this door information + * via a TSD lookup on the privdoor key. + */ +struct privdoor_data { + int pd_dfd; + door_id_t pd_uniqid; + volatile uint32_t pd_refcnt; + door_xcreate_server_func_t *pd_crf; + void *pd_crcookie; + door_xcreate_thrsetup_func_t *pd_setupf; +}; + +static int door_xcreate_n(door_info_t *, struct privdoor_data *, int); + +/* + * door_create_cmn holds the privdoor data before kicking off server + * thread creation, all of which must succeed; if they don't then + * they return leaving the refcnt unchanged overall, and door_create_cmn + * releases its hold after revoking the door and we're done. Otherwise + * all n threads created add one each to the refcnt, and door_create_cmn + * drops its hold. If and when a server thread exits the key destructor + * function will be called, and we use that to decrement the reference + * count. We also decrement the reference count on door_unbind(). + * If ever we get the reference count to 0 then we will free that data. + */ +static void +privdoor_data_hold(struct privdoor_data *pdd) +{ + atomic_inc_32(&pdd->pd_refcnt); +} + +static void +privdoor_data_rele(struct privdoor_data *pdd) +{ + if (atomic_dec_32_nv(&pdd->pd_refcnt) == 0) + free(pdd); +} + +void +privdoor_destructor(void *data) +{ + privdoor_data_rele((struct privdoor_data *)data); +} /* * We park the ourselves in the kernel to serve as the "caller" for @@ -87,9 +143,10 @@ return (NULL); } -int -door_create(void (*f)(void *, char *, size_t, door_desc_t *, uint_t), - void *cookie, uint_t flags) +static int +door_create_cmn(door_server_procedure_t *f, void *cookie, uint_t flags, + door_xcreate_server_func_t *crf, door_xcreate_thrsetup_func_t *setupf, + void *crcookie, int nthread) { int d; @@ -107,6 +164,9 @@ return (-1); } + if (crf) + flags |= DOOR_PRIVCREATE; + /* * Doors are associated with the processes which created them. In * the face of forkall(), this gets quite complicated. To simplify @@ -117,7 +177,7 @@ enter_critical(self); if ((d = __door_create(f, cookie, flags)) < 0) { exit_critical(self); - return (-1); + return (-1); /* errno is set */ } mypid = getpid(); if (mypid != door_create_pid || @@ -150,25 +210,86 @@ (void *)(uintptr_t)mypid, THR_DAEMON, NULL); } - /* - * If this is the first door created in the process, or the door - * has a private pool, we need to kick off the thread pool now. - */ - if (do_create_first) - (*door_server_func)(NULL); - if (is_private) { door_info_t di; + /* + * Create the first thread(s) for this private door. + */ if (__door_info(d, &di) < 0) - return (-1); - (*door_server_func)(&di); + return (-1); /* errno is set */ + + /* + * This key must be available for lookup for all private + * door threads, whether associated with a door created via + * door_create or door_xcreate. + */ + (void) pthread_key_create_once_np(&privdoor_key, + privdoor_destructor); + + if (crf == NULL) { + (*door_server_func)(&di); + } else { + struct privdoor_data *pdd = malloc(sizeof (*pdd)); + + if (pdd == NULL) { + (void) door_revoke(d); + errno = ENOMEM; + return (-1); + } + + pdd->pd_dfd = d; + pdd->pd_uniqid = di.di_uniquifier; + pdd->pd_refcnt = 1; /* prevent free during xcreate_n */ + pdd->pd_crf = crf; + pdd->pd_crcookie = crcookie; + pdd->pd_setupf = setupf; + + if (!door_xcreate_n(&di, pdd, nthread)) { + int errnocp = errno; + + (void) door_revoke(d); + privdoor_data_rele(pdd); + errno = errnocp; + return (-1); + } else { + privdoor_data_rele(pdd); + } + } + } else if (do_create_first) { + /* First non-private door created in the process */ + (*door_server_func)(NULL); } return (d); } int +door_create(door_server_procedure_t *f, void *cookie, uint_t flags) +{ + if (flags & (DOOR_NO_DEPLETION_CB | DOOR_PRIVCREATE)) { + errno = EINVAL; + return (-1); + } + + return (door_create_cmn(f, cookie, flags, NULL, NULL, NULL, 1)); +} + +int +door_xcreate(door_server_procedure_t *f, void *cookie, uint_t flags, + door_xcreate_server_func_t *crf, door_xcreate_thrsetup_func_t *setupf, + void *crcookie, int nthread) +{ + if (flags & DOOR_PRIVCREATE || nthread < 1 || crf == NULL) { + errno = EINVAL; + return (-1); + } + + return (door_create_cmn(f, cookie, flags | DOOR_PRIVATE, + crf, setupf, crcookie, nthread)); +} + +int door_ucred(ucred_t **uc) { ucred_t *ucp = *uc; @@ -211,6 +332,26 @@ } int +door_unbind(void) +{ + struct privdoor_data *pdd; + int rv = __door_unbind(); + + /* + * If we were indeed bound to the door then check to see whether + * we are part of a door_xcreate'd door by checking for our TSD. + * If so, then clear the TSD for this key to avoid destructor + * callback on future thread exit, and release the private door data. + */ + if (rv == 0 && (pdd = pthread_getspecific(privdoor_key)) != NULL) { + (void) pthread_setspecific(privdoor_key, NULL); + privdoor_data_rele(pdd); + } + + return (rv); +} + +int door_return(char *data_ptr, size_t data_size, door_desc_t *desc_ptr, uint_t num_desc) { @@ -321,7 +462,337 @@ } /* - * Install a new server creation function. + * To start and synchronize a number of door service threads at once + * we use a struct door_xsync_shared shared by all threads, and + * a struct door_xsync for each thread. While each thread + * has its own startup state, all such state are protected by the same + * shared lock. This could cause a little contention but it is a one-off + * cost at door creation. + */ +enum door_xsync_state { + DOOR_XSYNC_CREATEWAIT = 0x1c8c8c80, /* awaits creation handshake */ + DOOR_XSYNC_ABORT, /* aborting door_xcreate */ + DOOR_XSYNC_ABORTED, /* thread heeded abort request */ + DOOR_XSYNC_MAXCONCUR, /* create func decided no more */ + DOOR_XSYNC_CREATEFAIL, /* thr_create/pthread_create failure */ + DOOR_XSYNC_SETSPEC_FAIL, /* setspecific failed */ + DOOR_XSYNC_BINDFAIL, /* door_bind failed */ + DOOR_XSYNC_BOUND, /* door_bind succeeded */ + DOOR_XSYNC_ENTER_SERVICE /* Go on to door_return */ +}; + +/* These stats are incremented non-atomically - indicative only */ +uint64_t door_xcreate_n_stats[DOOR_XSYNC_ENTER_SERVICE - + DOOR_XSYNC_CREATEWAIT + 1]; + +struct door_xsync_shared { + pthread_mutex_t lock; + pthread_cond_t cv_m2s; + pthread_cond_t cv_s2m; + struct privdoor_data *pdd; + volatile uint32_t waiting; +}; + +struct door_xsync { + volatile enum door_xsync_state state; + struct door_xsync_shared *sharedp; +}; + +/* + * Thread start function that xcreated private doors must use in + * thr_create or pthread_create. They must also use the argument we + * provide. We: + * + * o call a thread setup function if supplied, or apply sensible defaults + * o bind the newly-created thread to the door it will service + * o synchronize with door_xcreate to indicate that we have successfully + * bound to the door; door_xcreate will not return until all + * requested threads have at least bound + * o enter service with door_return quoting magic sentinel args + */ +void * +door_xcreate_startf(void *arg) +{ + struct door_xsync *xsp = (struct door_xsync *)arg; + struct door_xsync_shared *xssp = xsp->sharedp; + struct privdoor_data *pdd = xssp->pdd; + enum door_xsync_state next_state; + + privdoor_data_hold(pdd); + if (pthread_setspecific(privdoor_key, (const void *)pdd) != 0) { + next_state = DOOR_XSYNC_SETSPEC_FAIL; + privdoor_data_rele(pdd); + goto handshake; + } + + if (pdd->pd_setupf != NULL) { + (pdd->pd_setupf)(pdd->pd_crcookie); + } else { + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + } + + if (door_bind(pdd->pd_dfd) == 0) + next_state = DOOR_XSYNC_BOUND; + else + next_state = DOOR_XSYNC_BINDFAIL; + +handshake: + (void) pthread_mutex_lock(&xssp->lock); + + ASSERT(xsp->state == DOOR_XSYNC_CREATEWAIT || + xsp->state == DOOR_XSYNC_ABORT); + + if (xsp->state == DOOR_XSYNC_ABORT) + next_state = DOOR_XSYNC_ABORTED; + + xsp->state = next_state; + + if (--xssp->waiting == 0) + (void) pthread_cond_signal(&xssp->cv_s2m); + + if (next_state != DOOR_XSYNC_BOUND) { + (void) pthread_mutex_unlock(&xssp->lock); + return (NULL); /* thread exits, key destructor called */ + } + + while (xsp->state == DOOR_XSYNC_BOUND) + (void) pthread_cond_wait(&xssp->cv_m2s, &xssp->lock); + + next_state = xsp->state; + ASSERT(next_state == DOOR_XSYNC_ENTER_SERVICE || + next_state == DOOR_XSYNC_ABORT); + + if (--xssp->waiting == 0) + (void) pthread_cond_signal(&xssp->cv_s2m); + + (void) pthread_mutex_unlock(&xssp->lock); /* xssp/xsp can be freed */ + + if (next_state == DOOR_XSYNC_ABORT) + return (NULL); /* thread exits, key destructor called */ + + (void) door_return(NULL, 0, NULL, 0); + return (NULL); +} + +static int +door_xcreate_n(door_info_t *dip, struct privdoor_data *pdd, int n) +{ + struct door_xsync_shared *xssp; + struct door_xsync *xsp; + int i, failidx = -1; + int isdepcb = 0; + int failerrno; + int bound = 0; +#ifdef _STACK_GROWS_DOWNWARD + int stkdir = -1; +#else + int stkdir = 1; +#endif + int rv = 0; + + /* + * If we're called during door creation then we have the + * privdoor_data. If we're called as part of a depletion callback + * then the current thread has the privdoor_data as TSD. + */ + if (pdd == NULL) { + isdepcb = 1; + if ((pdd = pthread_getspecific(privdoor_key)) == NULL) + thr_panic("door_xcreate_n - no privdoor_data " + "on existing server thread"); + } + + /* + * Allocate on our stack. We'll pass pointers to this to the + * newly-created threads, therefore this function must not return until + * we have synced with server threads that are created. + * We do not limit the number of threads so begin by checking + * that we have space on the stack for this. + */ + { + size_t sz = sizeof (*xssp) + n * sizeof (*xsp) + 32; + char dummy; + + if (!stack_inbounds(&dummy + stkdir * sz)) { + errno = E2BIG; + return (0); + } + } + + if ((xssp = alloca(sizeof (*xssp))) == NULL || + (xsp = alloca(n * sizeof (*xsp))) == NULL) { + errno = E2BIG; + return (0); + } + + (void) pthread_mutex_init(&xssp->lock, NULL); + (void) pthread_cond_init(&xssp->cv_m2s, NULL); + (void) pthread_cond_init(&xssp->cv_s2m, NULL); + xssp->pdd = pdd; + xssp->waiting = 0; + + (void) pthread_mutex_lock(&xssp->lock); + + for (i = 0; failidx == -1 && i < n; i++) { + xsp[i].sharedp = xssp; + membar_producer(); /* xssp and xsp[i] for new thread */ + + switch ((pdd->pd_crf)(dip, door_xcreate_startf, + (void *)&xsp[i], pdd->pd_crcookie)) { + case 1: + /* + * Thread successfully created. Set mailbox + * state and increment the number we have to + * sync with. + */ + xsp[i].state = DOOR_XSYNC_CREATEWAIT; + xssp->waiting++; + break; + case 0: + /* + * Elected to create no further threads. OK for + * a depletion callback, but not during door_xcreate. + */ + xsp[i].state = DOOR_XSYNC_MAXCONCUR; + if (!isdepcb) { + failidx = i; + failerrno = EINVAL; + } + break; + case -1: + /* + * Thread creation was attempted but failed. + */ + xsp[i].state = DOOR_XSYNC_CREATEFAIL; + failidx = i; + failerrno = EPIPE; + break; + default: + /* + * The application-supplied function did not return + * -1/0/1 - best we can do is panic because anything + * else is harder to debug. + */ + thr_panic("door server create function illegal return"); + /*NOTREACHED*/ + } + } + + /* + * On initial creation all must succeed; if not then abort + */ + if (!isdepcb && failidx != -1) { + for (i = 0; i < failidx; i++) + if (xsp[i].state == DOOR_XSYNC_CREATEWAIT) + xsp[i].state = DOOR_XSYNC_ABORT; + } + + /* + * Wait for thread startup handshake to complete for all threads + */ + while (xssp->waiting) + (void) pthread_cond_wait(&xssp->cv_s2m, &xssp->lock); + + /* + * If we are aborting for a failed thread create in door_xcreate + * then we're done. + */ + if (!isdepcb && failidx != -1) { + rv = 0; + goto out; /* lock held, failerrno is set */ + } + + /* + * Did we all succeed in binding? + */ + for (i = 0; i < n; i++) { + int statidx = xsp[i].state - DOOR_XSYNC_CREATEWAIT; + + door_xcreate_n_stats[statidx]++; + if (xsp[i].state == DOOR_XSYNC_BOUND) + bound++; + } + + if (bound == n) { + rv = 1; + } else { + failerrno = EBADF; + rv = 0; + } + + /* + * During door_xcreate all must succeed in binding - if not then + * we command even those that did bind to abort. Threads that + * did not get as far as binding have already exited. + */ + for (i = 0; i < n; i++) { + if (xsp[i].state == DOOR_XSYNC_BOUND) { + xsp[i].state = (rv == 1 || isdepcb) ? + DOOR_XSYNC_ENTER_SERVICE : DOOR_XSYNC_ABORT; + xssp->waiting++; + } + } + + (void) pthread_cond_broadcast(&xssp->cv_m2s); + + while (xssp->waiting) + (void) pthread_cond_wait(&xssp->cv_s2m, &xssp->lock); + +out: + (void) pthread_mutex_unlock(&xssp->lock); + (void) pthread_mutex_destroy(&xssp->lock); + (void) pthread_cond_destroy(&xssp->cv_m2s); + (void) pthread_cond_destroy(&xssp->cv_s2m); + + if (rv == 0) + errno = failerrno; + + return (rv); +} + +/* + * Call the server creation function to give it the opportunity to + * create more threads. Called during a door invocation when we + * return from door_return(NULL,0, NULL, 0) and notice that we're + * running on the last available thread. + */ +void +door_depletion_cb(door_info_t *dip) +{ + if (dip == NULL) { + /* + * Non-private doors always use door_server_func. + */ + (*door_server_func)(NULL); + return; + } + + if (dip->di_attributes & DOOR_NO_DEPLETION_CB) { + /* + * Private, door_xcreate'd door specified no callbacks. + */ + return; + } else if (!(dip->di_attributes & DOOR_PRIVCREATE)) { + /* + * Private door with standard/legacy creation semantics. + */ + dip->di_attributes |= DOOR_DEPLETION_CB; + (*door_server_func)(dip); + return; + } else { + /* + * Private, door_xcreate'd door. + */ + dip->di_attributes |= DOOR_DEPLETION_CB; + (void) door_xcreate_n(dip, NULL, 1); + } +} + +/* + * Install a new server creation function. The appointed function + * will receieve depletion callbacks for non-private doors and private + * doors created with door_create(..., DOOR_PRIVATE). */ door_server_func_t * door_server_create(door_server_func_t *create_func) @@ -337,6 +808,7 @@ } /* + * Thread start function for door_create_server() below. * Create door server threads with cancellation(5) disabled. */ static void * @@ -349,7 +821,7 @@ } /* - * The default server thread creation routine. + * The default door_server_func_t. */ /* ARGSUSED */ static void
--- a/usr/src/lib/libc/sparc/Makefile.com Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libc/sparc/Makefile.com Thu Nov 19 15:28:11 2009 +1100 @@ -1134,7 +1134,8 @@ $(TIL:%=pics/%) := CFLAGS += $(LIBCBASE)/threads/sparc.il # special kludge for inlines with 'cas': -pics/rwlock.o pics/synch.o pics/lwp.o := sparc_CFLAGS += -_gcc=-Wa,-xarch=v8plus +pics/rwlock.o pics/synch.o pics/lwp.o pics/door_calls.o := \ + sparc_CFLAGS += -_gcc=-Wa,-xarch=v8plus # Files in port/fp subdirectory that need base.il inline template IL= \
--- a/usr/src/lib/libc/sparc/sys/door.s Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libc/sparc/sys/door.s Thu Nov 19 15:28:11 2009 +1100 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,7 +37,6 @@ ANSI_PRAGMA_WEAK2(door_info,__door_info,function) ANSI_PRAGMA_WEAK2(door_revoke,__door_revoke,function) ANSI_PRAGMA_WEAK2(door_setparam,__door_setparam,function) - ANSI_PRAGMA_WEAK2(door_unbind,__door_unbind,function) /* * Offsets within struct door_results @@ -105,16 +104,7 @@ * this is the last server thread - call creation func for more */ save %sp, -SA(MINFRAME), %sp - PIC_SETUP(g1) -#ifdef __sparcv9 - sethi %hi(door_server_func), %g5 - or %g5, %lo(door_server_func), %g5 - ldn [%g5 + %g1], %g1 -#else - ldn [%g1 + door_server_func], %g1 -#endif - ldn [%g1], %g1 - jmpl %g1, %o7 /* call create function */ + call door_depletion_cb ldn [%fp + DOOR_INFO_PTR], %o0 /* (delay) load door_info ptr */ restore 1:
--- a/usr/src/lib/libdoor/common/llib-ldoor Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libdoor/common/llib-ldoor Thu Nov 19 15:28:11 2009 +1100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -23,16 +22,18 @@ /* PROTOLIB1 */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" #include <door.h> /* door_calls.c */ int door_create(void (*)(void *, char *, size_t, door_desc_t *, uint_t), void *, uint_t); +int door_xcreate(door_server_procedure_t *, void *, uint_t, + door_xcreate_server_func_t *, door_xcreate_thrsetup_func_t *, + void *, int); int door_revoke(int); int door_info(int, door_info_t *); int door_call(int, door_arg_t *);
--- a/usr/src/lib/libdoor/common/mapfile-vers Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libdoor/common/mapfile-vers Thu Nov 19 15:28:11 2009 +1100 @@ -48,6 +48,7 @@ door_server_create = FUNCTION; door_ucred = FUNCTION; door_unbind = FUNCTION; + door_xcreate = FUNCTION; local: *; };
--- a/usr/src/lib/libds/common/libds.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libds/common/libds.c Thu Nov 19 15:28:11 2009 +1100 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -316,7 +316,7 @@ } if (sysevent_evc_subscribe(ds_evchan, ds_sid_name, EC_VLDS, ds_recv, NULL, 0) != 0) { - sysevent_evc_unbind(ds_evchan); + (void) sysevent_evc_unbind(ds_evchan); ds_evchan = NULL; return (errno); }
--- a/usr/src/lib/libsysevent/libevchannel.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libsysevent/libevchannel.c Thu Nov 19 15:28:11 2009 +1100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <ctype.h> #include <fcntl.h> @@ -35,6 +32,9 @@ #include <stddef.h> #include <stdlib.h> #include <strings.h> +#include <pthread.h> +#include <atomic.h> +#include <signal.h> #include <sys/types.h> #include <sys/varargs.h> #include <sys/sysevent.h> @@ -54,8 +54,34 @@ * sysevent_evc_control - various channel based control operation */ +static void kill_door_servers(evchan_subscr_t *); + #define misaligned(p) ((uintptr_t)(p) & 3) /* 4-byte alignment required */ +static pthread_key_t nrkey = PTHREAD_ONCE_KEY_NP; + +/* + * If the current thread is a door server thread servicing a door created + * for us in sysevent_evc_xsubscribe, then an attempt to unsubscribe from + * within door invocation context on the same channel will deadlock in the + * kernel waiting for our own invocation to complete. Such calls are + * forbidden, and we abort if they are encountered (better than hanging + * unkillably). + * + * We'd like to offer this detection to subscriptions established with + * sysevent_evc_subscribe, but we don't have control over the door service + * threads in that case. Perhaps the fix is to always use door_xcreate + * even for sysevent_evc_subscribe? + */ +static boolean_t +will_deadlock(evchan_t *scp) +{ + evchan_subscr_t *subp = pthread_getspecific(nrkey); + evchan_impl_hdl_t *hdl = EVCHAN_IMPL_HNDL(scp); + + return (subp != NULL && subp->ev_subhead == hdl ? B_TRUE : B_FALSE); +} + /* * Check syntax of a channel name */ @@ -173,14 +199,18 @@ /* * sysevent_evc_unbind - Unbind from previously bound/created channel */ -void +int sysevent_evc_unbind(evchan_t *scp) { sev_unsubscribe_args_t uargs; - evchan_subscr_t *subp, *tofree; + evchan_subscr_t *subp; + int errcp; if (scp == NULL || misaligned(scp)) - return; + return (errno = EINVAL); + + if (will_deadlock(scp)) + return (errno = EDEADLK); (void) mutex_lock(EV_LOCK(scp)); @@ -195,19 +225,24 @@ * drained. */ if (ioctl(EV_FD(scp), SEV_UNSUBSCRIBE, (intptr_t)&uargs) != 0) { + errcp = errno; (void) mutex_unlock(EV_LOCK(scp)); - return; + return (errno = errcp); } } - subp = (evchan_subscr_t *)(void*)EV_SUB(scp); - while (subp->evsub_next != NULL) { - tofree = subp->evsub_next; - subp->evsub_next = tofree->evsub_next; - if (door_revoke(tofree->evsub_door_desc) != 0 && errno == EPERM) - (void) close(tofree->evsub_door_desc); - free(tofree->evsub_sid); - free(tofree); + while ((subp = EV_SUB_NEXT(scp)) != NULL) { + EV_SUB_NEXT(scp) = subp->evsub_next; + + /* If door_xcreate was applied we can clean up */ + if (subp->evsub_attr) + kill_door_servers(subp); + + if (door_revoke(subp->evsub_door_desc) != 0 && errno == EPERM) + (void) close(subp->evsub_door_desc); + + free(subp->evsub_sid); + free(subp); } (void) mutex_unlock(EV_LOCK(scp)); @@ -219,6 +254,8 @@ (void) close(EV_FD(scp)); (void) mutex_destroy(EV_LOCK(scp)); free(scp); + + return (0); } /* @@ -287,6 +324,13 @@ evchan_subscr_t *subp = EVCHAN_SUBSCR(cookie); int rval = 0; + /* + * If we've been invoked simply to kill the thread then + * exit now. + */ + if (subp->evsub_state == EVCHAN_SUB_STATE_CLOSING) + pthread_exit(NULL); + if (args == NULL || alen <= (size_t)0) { /* Skip callback execution */ rval = EINVAL; @@ -304,13 +348,106 @@ (void) door_return(args, alen, NULL, 0); } +static pthread_once_t xsub_thrattr_once = PTHREAD_ONCE_INIT; +static pthread_attr_t xsub_thrattr; + +static void +xsub_thrattr_init(void) +{ + (void) pthread_attr_init(&xsub_thrattr); + (void) pthread_attr_setdetachstate(&xsub_thrattr, + PTHREAD_CREATE_DETACHED); + (void) pthread_attr_setscope(&xsub_thrattr, PTHREAD_SCOPE_SYSTEM); +} + /* - * sysevent_evc_subscribe - Subscribe to an existing event channel + * Our door server create function is only called during initial + * door_xcreate since we specify DOOR_NO_DEPLETION_CB. */ int -sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class, +xsub_door_server_create(door_info_t *dip, void *(*startf)(void *), + void *startfarg, void *cookie) +{ + evchan_subscr_t *subp = EVCHAN_SUBSCR(cookie); + struct sysevent_subattr_impl *xsa = subp->evsub_attr; + pthread_attr_t *thrattr; + sigset_t oset; + int err; + + if (subp->evsub_state == EVCHAN_SUB_STATE_CLOSING) + return (0); /* shouldn't happen, but just in case */ + + /* + * If sysevent_evc_xsubscribe was called electing to use a + * different door server create function then let it take it + * from here. + */ + if (xsa->xs_thrcreate) { + return (xsa->xs_thrcreate(dip, startf, startfarg, + xsa->xs_thrcreate_cookie)); + } + + if (xsa->xs_thrattr == NULL) { + (void) pthread_once(&xsub_thrattr_once, xsub_thrattr_init); + thrattr = &xsub_thrattr; + } else { + thrattr = xsa->xs_thrattr; + } + + (void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset); + err = pthread_create(NULL, thrattr, startf, startfarg); + (void) pthread_sigmask(SIG_SETMASK, &oset, NULL); + + return (err == 0 ? 1 : -1); +} + +void +xsub_door_server_setup(void *cookie) +{ + evchan_subscr_t *subp = EVCHAN_SUBSCR(cookie); + struct sysevent_subattr_impl *xsa = subp->evsub_attr; + + if (xsa->xs_thrsetup == NULL) { + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + } + + (void) pthread_setspecific(nrkey, (void *)subp); + + if (xsa->xs_thrsetup) + xsa->xs_thrsetup(xsa->xs_thrsetup_cookie); +} + +/* + * Cause private door server threads to exit. We have already performed the + * unsubscribe ioctl which stops new invocations and waits until all + * existing invocations are complete. So all server threads should be + * blocked in door_return. The door has not yet been revoked. We will + * invoke repeatedly after setting the evsub_state to be noticed on + * wakeup; each invocation will result in the death of one server thread. + * + * You'd think it would be easier to kill these threads, such as through + * pthread_cancel. Unfortunately door_return is not a cancellation point, + * and if you do cancel a thread blocked in door_return the EINTR check in + * the door_return assembly logic causes us to loop with EINTR forever! + */ +static void +kill_door_servers(evchan_subscr_t *subp) +{ + door_arg_t da; + int i; + + bzero(&da, sizeof (da)); + subp->evsub_state = EVCHAN_SUB_STATE_CLOSING; + membar_producer(); + + (void) door_call(subp->evsub_door_desc, &da); +} + +static int +sysevent_evc_subscribe_cmn(evchan_t *scp, const char *sid, const char *class, int (*event_handler)(sysevent_t *ev, void *cookie), - void *cookie, uint32_t flags) + void *cookie, uint32_t flags, struct sysevent_subattr_impl *xsa) { evchan_subscr_t *subp; int upcall_door; @@ -342,6 +479,9 @@ return (errno = EINVAL); } + if (pthread_key_create_once_np(&nrkey, NULL) != 0) + return (errno); /* ENOMEM or EAGAIN */ + /* Create subscriber data */ if ((subp = calloc(1, sizeof (evchan_subscr_t))) == NULL) { return (errno); @@ -361,8 +501,29 @@ class_len = 0; } - upcall_door = door_create(door_upcall, (void *)subp, - DOOR_REFUSE_DESC | DOOR_NO_CANCEL); + /* + * Fill this in now for the xsub_door_server_setup dance + */ + subp->ev_subhead = EVCHAN_IMPL_HNDL(scp); + subp->evsub_state = EVCHAN_SUB_STATE_ACTIVE; + + if (xsa == NULL) { + upcall_door = door_create(door_upcall, (void *)subp, + DOOR_REFUSE_DESC | DOOR_NO_CANCEL); + } else { + subp->evsub_attr = xsa; + + /* + * Create a private door with exactly one thread to + * service the callbacks (the GPEC kernel implementation + * serializes deliveries for each subscriber id). + */ + upcall_door = door_xcreate(door_upcall, (void *)subp, + DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB, + xsub_door_server_create, xsub_door_server_setup, + (void *)subp, 1); + } + if (upcall_door == -1) { ec = errno; free(subp->evsub_sid); @@ -377,8 +538,6 @@ (void) mutex_lock(EV_LOCK(scp)); - subp->ev_subhead = EVCHAN_IMPL_HNDL(scp); - uargs.sid.name = (uintptr_t)sid; uargs.sid.len = sid_len; uargs.class_info.name = (uintptr_t)class; @@ -388,6 +547,8 @@ if (ioctl(EV_FD(scp), SEV_SUBSCRIBE, (intptr_t)&uargs) != 0) { ec = errno; (void) mutex_unlock(EV_LOCK(scp)); + if (xsa) + kill_door_servers(subp); (void) door_revoke(upcall_door); free(subp->evsub_sid); free(subp); @@ -404,27 +565,145 @@ } /* + * sysevent_evc_subscribe - subscribe to an existing event channel + * using a non-private door (which will create as many server threads + * as the apparent maximum concurrency requirements suggest). + */ +int +sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class, + int (*event_handler)(sysevent_t *ev, void *cookie), + void *cookie, uint32_t flags) +{ + return (sysevent_evc_subscribe_cmn(scp, sid, class, event_handler, + cookie, flags, NULL)); +} + +static void +subattr_dfltinit(struct sysevent_subattr_impl *xsa) +{ + (void) sigfillset(&xsa->xs_sigmask); + (void) sigdelset(&xsa->xs_sigmask, SIGABRT); +} + +static struct sysevent_subattr_impl dfltsa; +pthread_once_t dfltsa_inited = PTHREAD_ONCE_INIT; + +static void +init_dfltsa(void) +{ + subattr_dfltinit(&dfltsa); +} + +/* + * sysevent_evc_subscribe - subscribe to an existing event channel + * using a private door with control over thread creation. + */ +int +sysevent_evc_xsubscribe(evchan_t *scp, const char *sid, const char *class, + int (*event_handler)(sysevent_t *ev, void *cookie), + void *cookie, uint32_t flags, sysevent_subattr_t *attr) +{ + struct sysevent_subattr_impl sa; + struct sysevent_subattr_impl *xsa; + + if (attr != NULL) { + xsa = (struct sysevent_subattr_impl *)attr; + } else { + xsa = &dfltsa; + (void) pthread_once(&dfltsa_inited, init_dfltsa); + } + + return (sysevent_evc_subscribe_cmn(scp, sid, class, event_handler, + cookie, flags, xsa)); +} + +sysevent_subattr_t * +sysevent_subattr_alloc(void) +{ + struct sysevent_subattr_impl *xsa = calloc(1, sizeof (*xsa)); + + if (xsa != NULL) + subattr_dfltinit(xsa); + + return (xsa != NULL ? (sysevent_subattr_t *)xsa : NULL); +} + +void +sysevent_subattr_free(sysevent_subattr_t *attr) +{ + struct sysevent_subattr_impl *xsa = + (struct sysevent_subattr_impl *)attr; + + free(xsa); +} + +void +sysevent_subattr_thrcreate(sysevent_subattr_t *attr, + door_xcreate_server_func_t *thrcreate, void *cookie) +{ + struct sysevent_subattr_impl *xsa = + (struct sysevent_subattr_impl *)attr; + + xsa->xs_thrcreate = thrcreate; + xsa->xs_thrcreate_cookie = cookie; +} + +void +sysevent_subattr_thrsetup(sysevent_subattr_t *attr, + door_xcreate_thrsetup_func_t *thrsetup, void *cookie) +{ + struct sysevent_subattr_impl *xsa = + (struct sysevent_subattr_impl *)attr; + + xsa->xs_thrsetup = thrsetup; + xsa->xs_thrsetup_cookie = cookie; +} + +void +sysevent_subattr_sigmask(sysevent_subattr_t *attr, sigset_t *set) +{ + struct sysevent_subattr_impl *xsa = + (struct sysevent_subattr_impl *)attr; + + if (set) { + xsa->xs_sigmask = *set; + } else { + (void) sigfillset(&xsa->xs_sigmask); + (void) sigdelset(&xsa->xs_sigmask, SIGABRT); + } +} + +void +sysevent_subattr_thrattr(sysevent_subattr_t *attr, pthread_attr_t *thrattr) +{ + struct sysevent_subattr_impl *xsa = + (struct sysevent_subattr_impl *)attr; + + xsa->xs_thrattr = thrattr; +} + +/* * sysevent_evc_unsubscribe - Unsubscribe from an existing event channel */ -void +int sysevent_evc_unsubscribe(evchan_t *scp, const char *sid) { int all_subscribers = 0; sev_unsubscribe_args_t uargs; - evchan_subscr_t *subp, *tofree; + evchan_subscr_t *subp, *prevsubp, *tofree; + int errcp; int rc; if (scp == NULL || misaligned(scp)) - return; + return (errno = EINVAL); if (sid == NULL || strlen(sid) == 0 || (strlen(sid) >= MAX_SUBID_LEN)) - return; + return (errno = EINVAL); /* No inheritance of binding handles via fork() */ - if (EV_PID(scp) != getpid()) { - return; - } + if (EV_PID(scp) != getpid()) + return (errno = EINVAL); if (strcmp(sid, EVCH_ALLSUB) == 0) { all_subscribers++; @@ -436,6 +715,9 @@ uargs.sid.len = strlen(sid) + 1; } + if (will_deadlock(scp)) + return (errno = EDEADLK); + (void) mutex_lock(EV_LOCK(scp)); /* @@ -444,31 +726,50 @@ rc = ioctl(EV_FD(scp), SEV_UNSUBSCRIBE, (intptr_t)&uargs); if (rc != 0) { + errcp = errno; (void) mutex_unlock(EV_LOCK(scp)); - return; + return (errno = errcp); /* EFAULT, ENXIO, EINVAL possible */ } - /* Search for the matching subscriber */ - subp = (evchan_subscr_t *)(void*)EV_SUB(scp); - while (subp->evsub_next != NULL) { - if (all_subscribers || - (strcmp(subp->evsub_next->evsub_sid, sid) == 0)) { + /* + * Search for the matching subscriber. If EVCH_ALLSUB was specified + * then the ioctl above will have returned 0 even if there are + * no subscriptions, so the initial EV_SUB_NEXT can be NULL. + */ + prevsubp = NULL; + subp = EV_SUB_NEXT(scp); + while (subp != NULL) { + if (all_subscribers || strcmp(subp->evsub_sid, sid) == 0) { + if (prevsubp == NULL) { + EV_SUB_NEXT(scp) = subp->evsub_next; + } else { + prevsubp->evsub_next = subp->evsub_next; + } - tofree = subp->evsub_next; - subp->evsub_next = tofree->evsub_next; + tofree = subp; + subp = subp->evsub_next; + + /* If door_xcreate was applied we can clean up */ + if (tofree->evsub_attr) + kill_door_servers(tofree); + (void) door_revoke(tofree->evsub_door_desc); free(tofree->evsub_sid); free(tofree); - /* Freed single subscriber already */ - if (all_subscribers == 0) { + + /* Freed single subscriber already? */ + if (all_subscribers == 0) break; - } - } else + } else { + prevsubp = subp; subp = subp->evsub_next; + } } (void) mutex_unlock(EV_LOCK(scp)); + + return (0); } /*
--- a/usr/src/lib/libsysevent/libsysevent.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libsysevent/libsysevent.c Thu Nov 19 15:28:11 2009 +1100 @@ -20,12 +20,10 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <fcntl.h> #include <errno.h> @@ -103,9 +101,9 @@ aligned_pub_sz = SE_ALIGN(pub_sz); payload_sz = (aligned_class_sz - sizeof (uint64_t)) + - (aligned_subclass_sz - sizeof (uint64_t)) + - (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) + - nvlist_sz; + (aligned_subclass_sz - sizeof (uint64_t)) + + (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) + + nvlist_sz; /* * Allocate event buffer plus additional payload overhead. @@ -163,8 +161,7 @@ } error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_POST_EVENT, - (uintptr_t)ev, (uintptr_t)SE_SIZE(ev), - (uintptr_t)eid, 0); + (uintptr_t)ev, (uintptr_t)SE_SIZE(ev), (uintptr_t)eid, 0); sysevent_free(ev); @@ -692,7 +689,7 @@ (void) sysevent_get_time(ev, &hrt); (void) fprintf(fp, "received sysevent id = 0X%llx:%llx\n", - hrt, (longlong_t)sysevent_get_seq(ev)); + hrt, (longlong_t)sysevent_get_seq(ev)); (void) fprintf(fp, "\tclass = %s\n", sysevent_get_class_name(ev)); (void) fprintf(fp, "\tsubclass = %s\n", sysevent_get_subclass_name(ev)); if ((vendor = sysevent_get_vendor_name(ev)) != NULL) { @@ -807,6 +804,7 @@ * is called in response to a door call to post an event. * */ +/*ARGSUSED*/ static void event_deliver_service(void *cookie, char *args, size_t alen, door_desc_t *ddp, uint_t ndid) @@ -1087,6 +1085,7 @@ } } +/*ARGSUSED*/ static int alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag) { @@ -1470,6 +1469,7 @@ * is called in response to a registration cache update. * */ +/*ARGSUSED*/ static void cache_update_service(void *cookie, char *args, size_t alen, door_desc_t *ddp, uint_t ndid) @@ -1490,6 +1490,7 @@ goto return_from_door; } + /* LINTED: E_BAD_PTR_CAST_ALIGN */ rargs = (struct reg_args *)args; shp = (sysevent_handle_t *)cookie; @@ -1833,8 +1834,8 @@ while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) { if (strcmp(m.mnt_mountp, "/var/run") == 0 && - strcmp(m.mnt_fstype, "tmpfs") == 0) { - (void) fclose(fp); + strcmp(m.mnt_fstype, "tmpfs") == 0) { + (void) fclose(fp); var_run_mounted = 1; break; } @@ -2127,7 +2128,7 @@ if ((SH_DOOR_DESC(shp) = door_create(event_deliver_service, (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { dprint("sysevent_bind_subscriber: door create failed: " - "%s\n", strerror(errno)); + "%s\n", strerror(errno)); error = EFAULT; goto fail; } @@ -2154,7 +2155,7 @@ /* Create an event handler thread */ if (thr_create(NULL, NULL, (void *(*)(void *))subscriber_event_handler, - shp, THR_BOUND, &sub_info->sp_handler_tid) != 0) { + shp, THR_BOUND, &sub_info->sp_handler_tid) != 0) { error = EFAULT; goto fail; }
--- a/usr/src/lib/libsysevent/libsysevent_impl.h Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libsysevent/libsysevent_impl.h Thu Nov 19 15:28:11 2009 +1100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,16 +18,15 @@ * * CDDL HEADER END */ + /* - * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LIBSYSEVENT_IMPL_H #define _LIBSYSEVENT_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -137,6 +135,15 @@ #define EV_SUB(evcp) (&(EVCHAN_IMPL_HNDL(evcp)->ev_sub)) #define EV_SUB_NEXT(evcp) (EVCHAN_IMPL_HNDL(evcp)->ev_sub.evchan_sub_next) +struct sysevent_subattr_impl { + door_xcreate_server_func_t *xs_thrcreate; + void *xs_thrcreate_cookie; + door_xcreate_thrsetup_func_t *xs_thrsetup; + void *xs_thrsetup_cookie; + pthread_attr_t *xs_thrattr; + sigset_t xs_sigmask; +}; + /* * Subscriber private data */ @@ -147,8 +154,13 @@ char *evsub_sid; /* identifier of subscriber */ void *evsub_cookie; /* subscriber cookie */ int (*evsub_func)(sysevent_t *, void *); /* subscriber event handler */ + struct sysevent_subattr_impl *evsub_attr; + uint32_t evsub_state; }; +#define EVCHAN_SUB_STATE_ACTIVE 1 +#define EVCHAN_SUB_STATE_CLOSING 2 + /* Access to subscriber data */ #define EVCHAN_SUBSCR(subp) ((evchan_subscr_t *)(subp))
--- a/usr/src/lib/libsysevent/llib-lsysevent Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libsysevent/llib-lsysevent Thu Nov 19 15:28:11 2009 +1100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -22,14 +21,12 @@ /*LINTLIBRARY*/ /*PROTOLIB1*/ /* - * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * usr/src/lib/libsysevent/llib-lsysevent */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <synch.h> #include <thread.h> #include "libsysevent.h" @@ -118,7 +115,7 @@ int sysevent_evc_bind(const char *channel_path, evchan_t **scpp, uint32_t flags); -void sysevent_evc_unbind(evchan_t *scp); +int sysevent_evc_unbind(evchan_t *scp); int sysevent_evc_publish(evchan_t *scp, const char *event_class, const char *event_subclass, const char *vendor, const char *pub_name, @@ -128,7 +125,24 @@ const char *event_class, int (*event_handler)(sysevent_t *ev, void *cookie), void *cookie, uint32_t flags); +int sysevent_evc_xsubscribe(evchan_t *scp, const char *sid, + const char *event_class, + int (*event_handler)(sysevent_t *ev, void *cookie), + void *cookie, uint32_t flags, + sysevent_subattr_t *xs); -void sysevent_evc_unsubscribe(evchan_t *scp, const char *sid); +int sysevent_evc_unsubscribe(evchan_t *scp, const char *sid); int sysevent_evc_control(evchan_t *scp, int cmd, ...); + +sysevent_subattr_t *sysevent_subattr_alloc(void); +void sysevent_subattr_free(sysevent_subattr_t *attr); + +void sysevent_subattr_thrcreate(sysevent_subattr_t *attr, + door_xcreate_server_func_t *func, void *cookie); +void sysevent_subattr_thrsetup(sysevent_subattr_t *attr, + door_xcreate_thrsetup_func_t *func, void *cookie); + +void sysevent_subattr_thrattr(sysevent_subattr_t *attr, + pthread_attr_t *thrattr); +
--- a/usr/src/lib/libsysevent/mapfile-vers Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libsysevent/mapfile-vers Thu Nov 19 15:28:11 2009 +1100 @@ -84,6 +84,7 @@ sysevent_evc_subscribe; sysevent_evc_unbind; sysevent_evc_unsubscribe; + sysevent_evc_xsubscribe; sysevent_get_class; sysevent_get_pub; sysevent_get_subclass; @@ -95,6 +96,12 @@ sysevent_unbind_publisher; sysevent_unbind_subscriber; sysevent_unregister_event; + sysevent_subattr_alloc; + sysevent_subattr_free; + sysevent_subattr_sigmask; + sysevent_subattr_thrattr; + sysevent_subattr_thrcreate; + sysevent_subattr_thrsetup; local: *; };
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/lib/libzonecfg/common/libzonecfg.c Thu Nov 19 15:28:11 2009 +1100 @@ -6060,7 +6060,7 @@ return (zevtchan); out1: - sysevent_evc_unbind(zevtchan->zn_eventchan); + (void) sysevent_evc_unbind(zevtchan->zn_eventchan); out2: (void) pthread_mutex_destroy(&zevtchan->zn_mutex); (void) pthread_cond_destroy(&zevtchan->zn_cond); @@ -6077,7 +6077,7 @@ int ret; - sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); + (void) sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); /* * Check that all evc threads have gone away. This should be * enforced by sysevent_evc_unbind.
--- a/usr/src/pkgdefs/SUNWfmd/prototype_com Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/pkgdefs/SUNWfmd/prototype_com Thu Nov 19 15:28:11 2009 +1100 @@ -34,6 +34,7 @@ f none usr/include/fm/fmd_agent.h 644 root bin f none usr/include/fm/diagcode.h 644 root bin f none usr/include/fm/libdiskstatus.h 644 root bin +f none usr/include/fm/libfmevent.h 644 root bin f none usr/include/fm/fmd_adm.h 644 root bin f none usr/include/fm/fmd_api.h 644 root bin f none usr/include/fm/fmd_fmri.h 644 root bin @@ -78,6 +79,8 @@ f none usr/lib/fm/fmd/plugins/disk-monitor.so 555 root bin f none usr/lib/fm/fmd/plugins/eft.conf 644 root bin f none usr/lib/fm/fmd/plugins/eft.so 555 root bin +f none usr/lib/fm/fmd/plugins/ext-event-transport.conf 644 root bin +f none usr/lib/fm/fmd/plugins/ext-event-transport.so 555 root bin f none usr/lib/fm/fmd/plugins/fabric-xlate.conf 644 root bin f none usr/lib/fm/fmd/plugins/fabric-xlate.so 555 root bin f none usr/lib/fm/fmd/plugins/fdd-msg.conf 644 root bin @@ -137,6 +140,10 @@ s none usr/lib/fm/libfmd_snmp.so=libfmd_snmp.so.1 f none usr/lib/fm/llib-lfmd_snmp 644 root bin f none usr/lib/fm/llib-lfmd_snmp.ln 644 root bin +f none usr/lib/fm/libfmevent.so.1 755 root bin +s none usr/lib/fm/libfmevent.so=libfmevent.so.1 +f none usr/lib/fm/llib-lfmevent 644 root bin +f none usr/lib/fm/llib-lfmevent.ln 644 root bin f none usr/lib/fm/libtopo.so.1 755 root bin s none usr/lib/fm/libtopo.so=libtopo.so.1 f none usr/lib/fm/llib-ltopo 644 root bin
--- a/usr/src/pkgdefs/SUNWfmd/prototype_i386 Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/pkgdefs/SUNWfmd/prototype_i386 Thu Nov 19 15:28:11 2009 +1100 @@ -33,6 +33,8 @@ s none usr/lib/fm/amd64/libdiagcode.so=./libdiagcode.so.1 f none usr/lib/fm/amd64/libdiskstatus.so.1 755 root bin s none usr/lib/fm/amd64/libdiskstatus.so=./libdiskstatus.so.1 +f none usr/lib/fm/amd64/libfmevent.so.1 755 root bin +s none usr/lib/fm/amd64/libfmevent.so=./libfmevent.so.1 f none usr/lib/fm/amd64/libfmd_adm.so.1 755 root bin s none usr/lib/fm/amd64/libfmd_adm.so=./libfmd_adm.so.1 f none usr/lib/fm/amd64/libfmd_log.so.1 755 root bin @@ -50,6 +52,7 @@ f none usr/lib/fm/amd64/llib-lfmd_log.ln 644 root bin f none usr/lib/fm/amd64/llib-lfmd_msg.ln 644 root bin f none usr/lib/fm/amd64/llib-lfmd_snmp.ln 644 root bin +f none usr/lib/fm/amd64/llib-lfmevent.ln 644 root bin f none usr/lib/fm/amd64/llib-ltopo.ln 644 root bin d none usr/lib/fm/fmd/schemes/amd64 755 root bin f none usr/lib/fm/fmd/schemes/amd64/cpu.so 555 root bin
--- a/usr/src/pkgdefs/SUNWfmd/prototype_sparc Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/pkgdefs/SUNWfmd/prototype_sparc Thu Nov 19 15:28:11 2009 +1100 @@ -56,6 +56,8 @@ s none usr/lib/fm/sparcv9/libdiagcode.so=libdiagcode.so.1 f none usr/lib/fm/sparcv9/libdiskstatus.so.1 755 root bin s none usr/lib/fm/sparcv9/libdiskstatus.so=libdiskstatus.so.1 +f none usr/lib/fm/sparcv9/libfmevent.so.1 755 root bin +s none usr/lib/fm/sparcv9/libfmevent.so=libfmevent.so.1 f none usr/lib/fm/sparcv9/llib-lfmd_agent.ln 644 root bin f none usr/lib/fm/sparcv9/llib-ldiagcode.ln 644 root bin f none usr/lib/fm/sparcv9/llib-ldiskstatus.ln 644 root bin @@ -77,6 +79,7 @@ f none usr/lib/fm/sparcv9/libfmd_snmp.so.1 755 root bin s none usr/lib/fm/sparcv9/libfmd_snmp.so=libfmd_snmp.so.1 f none usr/lib/fm/sparcv9/llib-lfmd_snmp.ln 644 root bin +f none usr/lib/fm/sparcv9/llib-lfmevent.ln 644 root bin f none usr/lib/fm/sparcv9/libtopo.so.1 755 root bin s none usr/lib/fm/sparcv9/libtopo.so=libtopo.so.1 f none usr/lib/fm/sparcv9/llib-ltopo.ln 644 root bin
--- a/usr/src/uts/common/io/bofi.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/uts/common/io/bofi.c Thu Nov 19 15:28:11 2009 +1100 @@ -784,7 +784,7 @@ if (reset_bus_ops(nexus_name, &save_bus_ops) == 0) return (DDI_FAILURE); - sysevent_evc_unbind(bofi_error_chan); + (void) sysevent_evc_unbind(bofi_error_chan); mutex_destroy(&clone_tab_mutex); mutex_destroy(&bofi_mutex);
--- a/usr/src/uts/common/os/evchannels.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/uts/common/os/evchannels.c Thu Nov 19 15:28:11 2009 +1100 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * This file contains the source of the general purpose event channel extension * to the sysevent framework. This implementation is made up mainly of four @@ -70,6 +68,9 @@ #define EVCH_EVQ_EVCOUNT(x) ((&(x)->eq_eventq)->sq_count) #define EVCH_EVQ_HIGHWM(x) ((&(x)->eq_eventq)->sq_highwm) +#define CH_HOLD_PEND 1 +#define CH_HOLD_PEND_INDEF 2 + struct evch_globals { evch_dlist_t evch_list; kmutex_t evch_list_lock; @@ -320,7 +321,8 @@ */ mutex_enter(&chp->ch_mutex); ASSERT(chp->ch_bindings == 0); - ASSERT(evch_dl_getnum(&chp->ch_subscr) != 0); + ASSERT(evch_dl_getnum(&chp->ch_subscr) != 0 || + chp->ch_holdpend == CH_HOLD_PEND_INDEF); /* Forcibly unsubscribe each remaining subscription */ while ((sdp = evch_dl_next(&chp->ch_subscr, NULL)) != NULL) { @@ -800,17 +802,50 @@ } /* + * Simple wildcarded match test of event class string 'class' to + * wildcarded subscription string 'pat'. Recursive only if + * 'pat' includes a wildcard, otherwise essentially just strcmp. + */ +static int +evch_clsmatch(char *class, const char *pat) +{ + char c; + + do { + if ((c = *pat++) == '\0') + return (*class == '\0'); + + if (c == '*') { + while (*pat == '*') + pat++; /* consecutive *'s can be collapsed */ + + if (*pat == '\0') + return (1); + + while (*class != '\0') { + if (evch_clsmatch(class++, pat) != 0) + return (1); + } + + return (0); + } + } while (c == *class++); + + return (0); +} + +/* * Sysevent filter callback routine. Enables event delivery only if it matches - * the event class string given by parameter cookie. + * the event class pattern string given by parameter cookie. */ static int evch_class_filter(void *ev, void *cookie) { - char *class = (char *)cookie; + const char *pat = (const char *)cookie; - if (class == NULL || strcmp(SE_CLASS_NAME(ev), class) == 0) { + if (pat == NULL || evch_clsmatch(SE_CLASS_NAME(ev), pat)) return (EVQ_DELIVER); - } + return (EVQ_IGNORE); } @@ -1061,8 +1096,13 @@ p->ch_maxsubscr = EVCH_MAX_SUBSCRIPTIONS; p->ch_maxbinds = evch_bindings_max; p->ch_ctime = gethrestime_sec(); - if (flags & EVCH_HOLD_PEND) { - p->ch_holdpend = 1; + + if (flags & (EVCH_HOLD_PEND | EVCH_HOLD_PEND_INDEF)) { + if (flags & EVCH_HOLD_PEND_INDEF) + p->ch_holdpend = CH_HOLD_PEND_INDEF; + else + p->ch_holdpend = CH_HOLD_PEND; + evch_evq_stop(p->ch_queue); } @@ -1114,9 +1154,13 @@ ASSERT(chp->ch_bindings > 0); chp->ch_bindings--; kmem_free(bp, sizeof (evch_bind_t)); - if (chp->ch_bindings == 0 && evch_dl_getnum(&chp->ch_subscr) == 0) { + if (chp->ch_bindings == 0 && evch_dl_getnum(&chp->ch_subscr) == 0 && + (chp->ch_nevents == 0 || chp->ch_holdpend != CH_HOLD_PEND_INDEF)) { /* - * No more bindings or persistent subscriber, destroy channel. + * No more bindings and no persistent subscriber(s). If there + * are no events in the channel then destroy the channel; + * otherwise destroy the channel only if we're not holding + * pending events indefinitely. */ mutex_exit(&chp->ch_mutex); evch_dl_del(&eg->evch_list, &chp->ch_link); @@ -1131,6 +1175,23 @@ mutex_exit(&eg->evch_list_lock); } +static int +wildcard_count(const char *class) +{ + int count = 0; + char c; + + if (class == NULL) + return (0); + + while ((c = *class++) != '\0') { + if (c == '*') + count++; + } + + return (count); +} + /* * Subscribe to a channel. dtype is either EVCH_DELKERN for kernel callbacks * or EVCH_DELDOOR for door upcall delivery to user land. Depending on dtype @@ -1155,6 +1216,14 @@ */ if (flags & ~(EVCH_SUB_KEEP | EVCH_SUB_DUMP)) return (EINVAL); + + /* + * Enforce a limit on the number of wildcards allowed in the class + * subscription string (limits recursion in pattern matching). + */ + if (wildcard_count(class) > EVCH_WILDCARD_MAX) + return (EINVAL); + /* * Check if we have already a subscription with that name and if we * have to reconnect the subscriber to a persistent subscription. @@ -1757,7 +1826,7 @@ return (evch_chbind(ch_name, (evch_bind_t **)scpp, flags)); } -void +int sysevent_evc_unbind(evchan_t *scp) { evch_bind_t *bp = (evch_bind_t *)scp; @@ -1765,6 +1834,8 @@ ASSERT(scp != NULL); evch_chunsubscribe(bp, NULL, 0); evch_chunbind(bp); + + return (0); } int @@ -1784,7 +1855,7 @@ (void *)callb, cookie, 0, 0)); } -void +int sysevent_evc_unsubscribe(evchan_t *scp, const char *sid) { ASSERT(scp != NULL && sid != NULL); @@ -1792,6 +1863,8 @@ sid = NULL; } evch_chunsubscribe((evch_bind_t *)scp, sid, 0); + + return (0); } /*
--- a/usr/src/uts/common/os/fm.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/uts/common/os/fm.c Thu Nov 19 15:28:11 2009 +1100 @@ -517,10 +517,10 @@ if (sysevent_evc_publish(error_chan, EC_FM, ESC_FM_ERROR, SUNW_VENDOR, FM_PUB, ereport, evc_flag) != 0) { atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1); - sysevent_evc_unbind(error_chan); + (void) sysevent_evc_unbind(error_chan); return; } - sysevent_evc_unbind(error_chan); + (void) sysevent_evc_unbind(error_chan); } /*
--- a/usr/src/uts/common/sys/door.h Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/uts/common/sys/door.h Thu Nov 19 15:28:11 2009 +1100 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,12 +30,29 @@ #ifndef _SYS_DOOR_H #define _SYS_DOOR_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif +/* + * Attributes associated with doors. + */ + +/* Attributes originally obtained from door_create operation */ +#define DOOR_UNREF 0x01 /* Deliver an unref notification with door */ +#define DOOR_PRIVATE 0x02 /* Use a private pool of server threads */ +#define DOOR_UNREF_MULTI 0x10 /* Deliver unref notification more than once */ +#define DOOR_REFUSE_DESC 0x40 /* Do not accept descriptors from callers */ +#define DOOR_NO_CANCEL 0x80 /* No server thread cancel on client abort */ +#define DOOR_NO_DEPLETION_CB 0x100 /* No thread create callbacks on depletion */ + +/* Attributes (additional) returned with door_info and door_desc_t data */ +#define DOOR_LOCAL 0x04 /* Descriptor is local to current process */ +#define DOOR_REVOKED 0x08 /* Door has been revoked */ +#define DOOR_IS_UNREF 0x20 /* Door is currently unreferenced */ +#define DOOR_PRIVCREATE 0x200 /* Door has a private thread creation func */ +#define DOOR_DEPLETION_CB 0x400 /* Set only during depletion callbacks */ + #if !defined(_ASM) #include <sys/types.h> @@ -62,25 +79,10 @@ /* Door descriptor passed to door_info to get current thread's binding */ #define DOOR_QUERY -2 -/* - * Attributes associated with doors. - */ - -/* Attributes originally obtained from door_create operation */ -#define DOOR_UNREF 0x01 /* Deliver an unref notification with door */ -#define DOOR_PRIVATE 0x02 /* Use a private pool of server threads */ -#define DOOR_UNREF_MULTI 0x10 /* Deliver unref notification more than once */ -#define DOOR_REFUSE_DESC 0x40 /* Do not accept descriptors from callers */ -#define DOOR_NO_CANCEL 0x80 /* No server thread cancel on client abort */ - -/* Attributes (additional) returned with door_info and door_desc_t data */ -#define DOOR_LOCAL 0x04 /* Descriptor is local to current process */ -#define DOOR_REVOKED 0x08 /* Door has been revoked */ -#define DOOR_IS_UNREF 0x20 /* Door is currently unreferenced */ - /* Masks of applicable flags */ #define DOOR_CREATE_MASK (DOOR_UNREF | DOOR_PRIVATE | \ - DOOR_UNREF_MULTI | DOOR_REFUSE_DESC | DOOR_NO_CANCEL) + DOOR_UNREF_MULTI | DOOR_REFUSE_DESC | DOOR_NO_CANCEL | \ + DOOR_NO_DEPLETION_CB | DOOR_PRIVCREATE) #define DOOR_KI_CREATE_MASK (DOOR_UNREF | DOOR_UNREF_MULTI) /* Mask of above attributes */
--- a/usr/src/uts/common/sys/sysevent.h Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/uts/common/sys/sysevent.h Thu Nov 19 15:28:11 2009 +1100 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,16 +18,15 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SYSEVENT_H #define _SYS_SYSEVENT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/nvpair.h> #ifdef __cplusplus @@ -164,18 +162,50 @@ #define EVCH_QWAIT 0x0008 /* Wait for slot in event queue */ /* - * Meaning of flags for subscribe/unsubscribe. Bits 0 to 7 are dedicated to - * the consolidation private interface. + * Meaning of flags for subscribe. Bits 8 to 15 are dedicated to + * the consolidation private interface, so flags defined here are restricted + * to the LSB. + * + * EVCH_SUB_KEEP indicates that this subscription should persist even if + * this subscriber id should die unexpectedly; matching events will be + * queued (up to a limit) and will be delivered if/when we restart again + * with the same subscriber id. */ -#define EVCH_SUB_KEEP 0x0001 +#define EVCH_SUB_KEEP 0x01 + +/* + * Subscriptions may be wildcarded, but we limit the number of + * wildcards permitted. + */ +#define EVCH_WILDCARD_MAX 10 + +/* + * Used in unsubscribe to indicate all subscriber ids for a channel. + */ #define EVCH_ALLSUB "all_subs" /* * Meaning of flags parameter of channel bind function + * + * EVCH_CREAT indicates to create a channel if not already present. + * + * EVCH_HOLD_PEND indicates that events should be published to this + * channel even if there are no matching subscribers present; when + * a subscriber belatedly binds to the channel and registers their + * subscriptions they will receive events that predate their bind. + * If the channel is closed, however, with no remaining bindings then + * the channel is destroyed. + * + * EVCH_HOLD_PEND_INDEF is a stronger version of EVCH_HOLD_PEND - + * even if the channel has no remaining bindings it will not be + * destroyed so long as events remain unconsumed. This is suitable for + * use with short-lived event producers that may bind to (create) the + * channel and exit before the intended consumer has started. */ -#define EVCH_CREAT 0x0001 /* Create a channel if not present */ +#define EVCH_CREAT 0x0001 #define EVCH_HOLD_PEND 0x0002 -#define EVCH_B_FLAGS 0x0003 /* All valid bits */ +#define EVCH_HOLD_PEND_INDEF 0x0004 +#define EVCH_B_FLAGS 0x0007 /* All valid bits */ /* * Meaning of commands of evc_control function @@ -186,37 +216,62 @@ #define EVCH_CMD_LAST EVCH_SET_CHAN_LEN /* Last command */ /* - * Event channel interface definitions + * Shared user/kernel event channel interface definitions */ -int sysevent_evc_bind(const char *, evchan_t **, uint32_t); -void sysevent_evc_unbind(evchan_t *); -int sysevent_evc_subscribe(evchan_t *, const char *, const char *, +extern int sysevent_evc_bind(const char *, evchan_t **, uint32_t); +extern int sysevent_evc_unbind(evchan_t *); +extern int sysevent_evc_subscribe(evchan_t *, const char *, const char *, int (*)(sysevent_t *, void *), void *, uint32_t); -void sysevent_evc_unsubscribe(evchan_t *, const char *); -int sysevent_evc_publish(evchan_t *, const char *, const char *, +extern int sysevent_evc_unsubscribe(evchan_t *, const char *); +extern int sysevent_evc_publish(evchan_t *, const char *, const char *, const char *, const char *, nvlist_t *, uint32_t); -int sysevent_evc_control(evchan_t *, int, ...); +extern int sysevent_evc_control(evchan_t *, int, ...); + +#ifndef _KERNEL + +/* + * Userland-only event channel interfaces + */ + +#include <door.h> + +typedef struct sysevent_subattr sysevent_subattr_t; -#ifdef _KERNEL +extern sysevent_subattr_t *sysevent_subattr_alloc(void); +extern void sysevent_subattr_free(sysevent_subattr_t *); + +extern void sysevent_subattr_thrattr(sysevent_subattr_t *, pthread_attr_t *); +extern void sysevent_subattr_sigmask(sysevent_subattr_t *, sigset_t *); + +extern void sysevent_subattr_thrcreate(sysevent_subattr_t *, + door_xcreate_server_func_t *, void *); +extern void sysevent_subattr_thrsetup(sysevent_subattr_t *, + door_xcreate_thrsetup_func_t *, void *); + +extern int sysevent_evc_xsubscribe(evchan_t *, const char *, const char *, + int (*)(sysevent_t *, void *), void *, uint32_t, sysevent_subattr_t *); + +#else /* * Kernel log_event interfaces. */ -int log_sysevent(sysevent_t *, int, sysevent_id_t *); +extern int log_sysevent(sysevent_t *, int, sysevent_id_t *); -sysevent_t *sysevent_alloc(char *, char *, char *, int); -void sysevent_free(sysevent_t *); -int sysevent_add_attr(sysevent_attr_list_t **, char *, sysevent_value_t *, int); -void sysevent_free_attr(sysevent_attr_list_t *); -int sysevent_attach_attributes(sysevent_t *, sysevent_attr_list_t *); -void sysevent_detach_attributes(sysevent_t *); -char *sysevent_get_class_name(sysevent_t *); -char *sysevent_get_subclass_name(sysevent_t *); -uint64_t sysevent_get_seq(sysevent_t *); -void sysevent_get_time(sysevent_t *, hrtime_t *); -size_t sysevent_get_size(sysevent_t *); -char *sysevent_get_pub(sysevent_t *); -int sysevent_get_attr_list(sysevent_t *, nvlist_t **); +extern sysevent_t *sysevent_alloc(char *, char *, char *, int); +extern void sysevent_free(sysevent_t *); +extern int sysevent_add_attr(sysevent_attr_list_t **, char *, + sysevent_value_t *, int); +extern void sysevent_free_attr(sysevent_attr_list_t *); +extern int sysevent_attach_attributes(sysevent_t *, sysevent_attr_list_t *); +extern void sysevent_detach_attributes(sysevent_t *); +extern char *sysevent_get_class_name(sysevent_t *); +extern char *sysevent_get_subclass_name(sysevent_t *); +extern uint64_t sysevent_get_seq(sysevent_t *); +extern void sysevent_get_time(sysevent_t *, hrtime_t *); +extern size_t sysevent_get_size(sysevent_t *); +extern char *sysevent_get_pub(sysevent_t *); +extern int sysevent_get_attr_list(sysevent_t *, nvlist_t **); #endif /* _KERNEL */
--- a/usr/src/uts/common/sys/sysevent_impl.h Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/uts/common/sys/sysevent_impl.h Thu Nov 19 15:28:11 2009 +1100 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -476,9 +476,9 @@ /* * Project private flags for sysevent_evc_subscribe. Bits 0 to 7 are reserved - * for the consolidation private interface. + * for the consolidation private interface, so we must use bits 8-15 here. */ -#define EVCH_SUB_DUMP 0x0100 +#define EVCH_SUB_DUMP (0x01 << 8) /* * Permission flags
--- a/usr/src/uts/sun4v/io/vlds.c Thu Nov 19 11:57:44 2009 +0800 +++ b/usr/src/uts/sun4v/io/vlds.c Thu Nov 19 15:28:11 2009 +1100 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -407,7 +407,7 @@ } if (sp->evchan) { - sysevent_evc_unbind(sp->evchan); + (void) sysevent_evc_unbind(sp->evchan); sp->evchan = NULL; }