summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Maltby <Gavin.Maltby@Sun.COM>2009-11-19 15:28:11 +1100
committerGavin Maltby <Gavin.Maltby@Sun.COM>2009-11-19 15:28:11 +1100
commit49b225e1cfa7bbf7738d4df0a03f18e3283426eb (patch)
treefec8a2ac5f26eef93ef906b43e2642f06bcba3a6
parent6dea387a9f9ddc2932a4c49a09384dfdcd5a703b (diff)
downloadillumos-joyent-49b225e1cfa7bbf7738d4df0a03f18e3283426eb.tar.gz
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
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c6
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_sysevent.c4
-rw-r--r--usr/src/cmd/fm/fminject/common/inj_main.c11
-rw-r--r--usr/src/cmd/fm/modules/common/Makefile7
-rw-r--r--usr/src/cmd/fm/modules/common/ext-event-transport/Makefile34
-rw-r--r--usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf52
-rw-r--r--usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h57
-rw-r--r--usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c70
-rw-r--r--usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c137
-rw-r--r--usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c8
-rw-r--r--usr/src/cmd/fps/fptest/fps_ereport_mod.c2
-rw-r--r--usr/src/head/door.h25
-rw-r--r--usr/src/lib/fm/Makefile20
-rw-r--r--usr/src/lib/fm/libfmevent/Makefile57
-rw-r--r--usr/src/lib/fm/libfmevent/Makefile.com78
-rw-r--r--usr/src/lib/fm/libfmevent/amd64/Makefile29
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_channels.h48
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_evaccess.c277
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_impl.h76
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_subscribe.c605
-rw-r--r--usr/src/lib/fm/libfmevent/common/fmev_util.c180
-rw-r--r--usr/src/lib/fm/libfmevent/common/libfmevent.h279
-rw-r--r--usr/src/lib/fm/libfmevent/common/llib-lfmevent30
-rw-r--r--usr/src/lib/fm/libfmevent/common/mapfile-vers73
-rw-r--r--usr/src/lib/fm/libfmevent/common/mkerror.sh65
-rw-r--r--usr/src/lib/fm/libfmevent/i386/Makefile28
-rw-r--r--usr/src/lib/fm/libfmevent/sparc/Makefile28
-rw-r--r--usr/src/lib/fm/libfmevent/sparcv9/Makefile29
-rw-r--r--usr/src/lib/libc/amd64/sys/door.s5
-rw-r--r--usr/src/lib/libc/i386/sys/door.s10
-rw-r--r--usr/src/lib/libc/port/mapfile-vers1
-rw-r--r--usr/src/lib/libc/port/threads/door_calls.c508
-rw-r--r--usr/src/lib/libc/sparc/Makefile.com3
-rw-r--r--usr/src/lib/libc/sparc/sys/door.s14
-rw-r--r--usr/src/lib/libdoor/common/llib-ldoor13
-rw-r--r--usr/src/lib/libdoor/common/mapfile-vers1
-rw-r--r--usr/src/lib/libds/common/libds.c4
-rw-r--r--usr/src/lib/libsysevent/libevchannel.c389
-rw-r--r--usr/src/lib/libsysevent/libsysevent.c27
-rw-r--r--usr/src/lib/libsysevent/libsysevent_impl.h24
-rw-r--r--usr/src/lib/libsysevent/llib-lsysevent30
-rw-r--r--usr/src/lib/libsysevent/mapfile-vers7
-rw-r--r--usr/src/lib/libzonecfg/common/libzonecfg.c4
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_com7
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_i3863
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_sparc3
-rw-r--r--usr/src/uts/common/io/bofi.c2
-rw-r--r--usr/src/uts/common/os/evchannels.c101
-rw-r--r--usr/src/uts/common/os/fm.c4
-rw-r--r--usr/src/uts/common/sys/door.h42
-rw-r--r--usr/src/uts/common/sys/sysevent.h123
-rw-r--r--usr/src/uts/common/sys/sysevent_impl.h6
-rw-r--r--usr/src/uts/sun4v/io/vlds.c4
53 files changed, 3411 insertions, 239 deletions
diff --git a/usr/src/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c b/usr/src/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c
index 8394716af1..4a452a7ad2 100644
--- a/usr/src/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c
+++ b/usr/src/cmd/dtrace/test/tst/common/sysevent/tst.post_chan.c
@@ -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 @@ main(int argc, char **argv)
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);
}
diff --git a/usr/src/cmd/fm/fmd/common/fmd_sysevent.c b/usr/src/cmd/fm/fmd/common/fmd_sysevent.c
index 4f70b28e37..1893289b00 100644
--- a/usr/src/cmd/fm/fmd/common/fmd_sysevent.c
+++ b/usr/src/cmd/fm/fmd/common/fmd_sysevent.c
@@ -533,8 +533,8 @@ void
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)
diff --git a/usr/src/cmd/fm/fminject/common/inj_main.c b/usr/src/cmd/fm/fminject/common/inj_main.c
index 5d91a451ba..bf4713ee3e 100644
--- a/usr/src/cmd/fm/fminject/common/inj_main.c
+++ b/usr/src/cmd/fm/fminject/common/inj_main.c
@@ -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 @@ sev_send(void *arg, nvlist_t *msg)
static void
sev_close(void *arg)
{
- sysevent_evc_unbind(arg);
+ (void) sysevent_evc_unbind(arg);
}
static inj_mode_ops_t sysevent_ops = {
diff --git a/usr/src/cmd/fm/modules/common/Makefile b/usr/src/cmd/fm/modules/common/Makefile
index a7facc87e3..9dc99bc05d 100644
--- a/usr/src/cmd/fm/modules/common/Makefile
+++ b/usr/src/cmd/fm/modules/common/Makefile
@@ -27,6 +27,9 @@ SUBDIRS = cpumem-retire \
disk-monitor \
disk-transport \
eversholt \
+ ext-event-transport \
+ fabric-xlate \
+ fdd-msg \
io-retire \
ip-transport \
sensor-transport \
@@ -34,8 +37,6 @@ SUBDIRS = cpumem-retire \
sp-monitor \
syslog-msgs \
zfs-diagnosis \
- zfs-retire \
- fdd-msg \
- fabric-xlate
+ zfs-retire
include ../../Makefile.subdirs
diff --git a/usr/src/cmd/fm/modules/common/ext-event-transport/Makefile b/usr/src/cmd/fm/modules/common/ext-event-transport/Makefile
new file mode 100644
index 0000000000..9639cc5177
--- /dev/null
+++ b/usr/src/cmd/fm/modules/common/ext-event-transport/Makefile
@@ -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
diff --git a/usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf b/usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf
new file mode 100644
index 0000000000..c98edaa48e
--- /dev/null
+++ b/usr/src/cmd/fm/modules/common/ext-event-transport/ext-event-transport.conf
@@ -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.*
+
diff --git a/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h
new file mode 100644
index 0000000000..959adb63f5
--- /dev/null
+++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt.h
@@ -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 */
diff --git a/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c
new file mode 100644
index 0000000000..7697468e2c
--- /dev/null
+++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_main.c
@@ -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);
+}
diff --git a/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c
new file mode 100644
index 0000000000..9ff06eb2e0
--- /dev/null
+++ b/usr/src/cmd/fm/modules/common/ext-event-transport/fmevt_outbound.c
@@ -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;
+ }
+}
diff --git a/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c b/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c
index 48e747a183..9f8b61b530 100644
--- a/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c
+++ b/usr/src/cmd/fm/modules/sun4u/fps-transport/fps-transport.c
@@ -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 @@ void
_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)
diff --git a/usr/src/cmd/fps/fptest/fps_ereport_mod.c b/usr/src/cmd/fps/fptest/fps_ereport_mod.c
index 3456cafc1b..9602ce719e 100644
--- a/usr/src/cmd/fps/fptest/fps_ereport_mod.c
+++ b/usr/src/cmd/fps/fptest/fps_ereport_mod.c
@@ -197,7 +197,7 @@ fps_post_ereport(nvlist_t *ereport)
(void) sleep(1);
(void) fflush(NULL);
- sysevent_evc_unbind(scp);
+ (void) sysevent_evc_unbind(scp);
return (0);
}
diff --git a/usr/src/head/door.h b/usr/src/head/door.h
index 091f552d1d..70d94f44d8 100644
--- a/usr/src/head/door.h
+++ b/usr/src/head/door.h
@@ -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 @@ extern "C" {
/*
* 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 @@ int door_setparam(int, int, size_t);
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
diff --git a/usr/src/lib/fm/Makefile b/usr/src/lib/fm/Makefile
index e5b3d8364c..775aba3fda 100644
--- a/usr/src/lib/fm/Makefile
+++ b/usr/src/lib/fm/Makefile
@@ -20,19 +20,13 @@
#
#
-# 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
-sparc_SUBDIRS = \
- libmdesc \
- libldom
-
-i386_SUBDIRS =
-
-SUBDIRS = \
+common_SUBDIRS = \
libfmd_agent \
libdiagcode \
libdiskstatus \
@@ -40,9 +34,17 @@ SUBDIRS = \
libfmd_log \
libfmd_msg \
libfmd_snmp \
- $($(MACH)_SUBDIRS) \
+ libfmevent \
topo
+sparc_SUBDIRS = \
+ libmdesc \
+ libldom
+
+i386_SUBDIRS =
+
+SUBDIRS = $(common_SUBDIRS) $($(MACH)_SUBDIRS)
+
libldom: libmdesc libfmd_agent
libfmd_snmp: libfmd_adm topo
diff --git a/usr/src/lib/fm/libfmevent/Makefile b/usr/src/lib/fm/libfmevent/Makefile
new file mode 100644
index 0000000000..bcbca44b61
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/Makefile
@@ -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
diff --git a/usr/src/lib/fm/libfmevent/Makefile.com b/usr/src/lib/fm/libfmevent/Makefile.com
new file mode 100644
index 0000000000..ed023a34d7
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/Makefile.com
@@ -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
diff --git a/usr/src/lib/fm/libfmevent/amd64/Makefile b/usr/src/lib/fm/libfmevent/amd64/Makefile
new file mode 100644
index 0000000000..e628bce86d
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/amd64/Makefile
@@ -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)
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_channels.h b/usr/src/lib/fm/libfmevent/common/fmev_channels.h
new file mode 100644
index 0000000000..033e4f52b3
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/fmev_channels.h
@@ -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 */
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c b/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c
new file mode 100644
index 0000000000..442cf0bc01
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/fmev_evaccess.c
@@ -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));
+}
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_impl.h b/usr/src/lib/fm/libfmevent/common/fmev_impl.h
new file mode 100644
index 0000000000..120660a27e
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/fmev_impl.h
@@ -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 */
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c b/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c
new file mode 100644
index 0000000000..a1727f9e58
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c
@@ -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));
+}
diff --git a/usr/src/lib/fm/libfmevent/common/fmev_util.c b/usr/src/lib/fm/libfmevent/common/fmev_util.c
new file mode 100644
index 0000000000..775cc14bf4
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/fmev_util.c
@@ -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);
+}
diff --git a/usr/src/lib/fm/libfmevent/common/libfmevent.h b/usr/src/lib/fm/libfmevent/common/libfmevent.h
new file mode 100644
index 0000000000..8cc06595bc
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/libfmevent.h
@@ -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 */
diff --git a/usr/src/lib/fm/libfmevent/common/llib-lfmevent b/usr/src/lib/fm/libfmevent/common/llib-lfmevent
new file mode 100644
index 0000000000..44c20c3d72
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/llib-lfmevent
@@ -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>
diff --git a/usr/src/lib/fm/libfmevent/common/mapfile-vers b/usr/src/lib/fm/libfmevent/common/mapfile-vers
new file mode 100644
index 0000000000..759c7ae124
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/mapfile-vers
@@ -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:
+ *;
+};
diff --git a/usr/src/lib/fm/libfmevent/common/mkerror.sh b/usr/src/lib/fm/libfmevent/common/mkerror.sh
new file mode 100644
index 0000000000..6a7467cb1e
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/common/mkerror.sh
@@ -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
diff --git a/usr/src/lib/fm/libfmevent/i386/Makefile b/usr/src/lib/fm/libfmevent/i386/Makefile
new file mode 100644
index 0000000000..c86be4377c
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/i386/Makefile
@@ -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)
diff --git a/usr/src/lib/fm/libfmevent/sparc/Makefile b/usr/src/lib/fm/libfmevent/sparc/Makefile
new file mode 100644
index 0000000000..c86be4377c
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/sparc/Makefile
@@ -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)
diff --git a/usr/src/lib/fm/libfmevent/sparcv9/Makefile b/usr/src/lib/fm/libfmevent/sparcv9/Makefile
new file mode 100644
index 0000000000..e628bce86d
--- /dev/null
+++ b/usr/src/lib/fm/libfmevent/sparcv9/Makefile
@@ -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)
diff --git a/usr/src/lib/libc/amd64/sys/door.s b/usr/src/lib/libc/amd64/sys/door.s
index f5fd6ec515..15061adf95 100644
--- a/usr/src/lib/libc/amd64/sys/door.s
+++ b/usr/src/lib/libc/amd64/sys/door.s
@@ -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 @@ door_restart:
/*
* 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
diff --git a/usr/src/lib/libc/i386/sys/door.s b/usr/src/lib/libc/i386/sys/door.s
index 2d348ebba8..1e5561c387 100644
--- a/usr/src/lib/libc/i386/sys/door.s
+++ b/usr/src/lib/libc/i386/sys/door.s
@@ -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 @@ door_restart:
* 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 @@ door_restart:
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)
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index d46bcae8e2..e788fca0aa 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -100,6 +100,7 @@ SUNW_1.23 { # SunOS 5.11 (Solaris 11)
door_setparam;
door_ucred;
door_unbind;
+ door_xcreate;
err;
errx;
faccessat;
diff --git a/usr/src/lib/libc/port/threads/door_calls.c b/usr/src/lib/libc/port/threads/door_calls.c
index 3dae1445d8..baa1f573aa 100644
--- a/usr/src/lib/libc/port/threads/door_calls.c
+++ b/usr/src/lib/libc/port/threads/door_calls.c
@@ -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 @@ extern int __door_return(caddr_t, size_t, door_return_desc_t *, caddr_t,
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 @@ door_unref_func(void *arg)
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 @@ door_create(void (*f)(void *, char *, size_t, door_desc_t *, uint_t),
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 @@ door_create(void (*f)(void *, char *, size_t, door_desc_t *, uint_t),
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 @@ door_create(void (*f)(void *, char *, size_t, door_desc_t *, uint_t),
(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 @@ door_cred(door_cred_t *dc)
}
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 @@ door_return(char *data_ptr, size_t data_size,
}
/*
- * 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 @@ door_server_create(door_server_func_t *create_func)
}
/*
+ * Thread start function for door_create_server() below.
* Create door server threads with cancellation(5) disabled.
*/
static void *
@@ -349,7 +821,7 @@ door_create_func(void *arg)
}
/*
- * The default server thread creation routine.
+ * The default door_server_func_t.
*/
/* ARGSUSED */
static void
diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com
index 9ee0e063c5..bda105c159 100644
--- a/usr/src/lib/libc/sparc/Makefile.com
+++ b/usr/src/lib/libc/sparc/Makefile.com
@@ -1134,7 +1134,8 @@ TIL= \
$(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= \
diff --git a/usr/src/lib/libc/sparc/sys/door.s b/usr/src/lib/libc/sparc/sys/door.s
index ce788bdbe8..8a45879130 100644
--- a/usr/src/lib/libc/sparc/sys/door.s
+++ b/usr/src/lib/libc/sparc/sys/door.s
@@ -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 @@ door_restart:
* 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:
diff --git a/usr/src/lib/libdoor/common/llib-ldoor b/usr/src/lib/libdoor/common/llib-ldoor
index eaaab62800..fb6075ca86 100644
--- a/usr/src/lib/libdoor/common/llib-ldoor
+++ b/usr/src/lib/libdoor/common/llib-ldoor
@@ -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 *);
diff --git a/usr/src/lib/libdoor/common/mapfile-vers b/usr/src/lib/libdoor/common/mapfile-vers
index efebf1514f..6f767b676a 100644
--- a/usr/src/lib/libdoor/common/mapfile-vers
+++ b/usr/src/lib/libdoor/common/mapfile-vers
@@ -48,6 +48,7 @@ SUNWprivate_1.1 {
door_server_create = FUNCTION;
door_ucred = FUNCTION;
door_unbind = FUNCTION;
+ door_xcreate = FUNCTION;
local:
*;
};
diff --git a/usr/src/lib/libds/common/libds.c b/usr/src/lib/libds/common/libds.c
index da4b95f524..274b90132a 100644
--- a/usr/src/lib/libds/common/libds.c
+++ b/usr/src/lib/libds/common/libds.c
@@ -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 @@ ds_init_sysev(void)
}
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);
}
diff --git a/usr/src/lib/libsysevent/libevchannel.c b/usr/src/lib/libsysevent/libevchannel.c
index a18a62b0dd..52f9b4641c 100644
--- a/usr/src/lib/libsysevent/libevchannel.c
+++ b/usr/src/lib/libsysevent/libevchannel.c
@@ -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_bind(const char *channel, evchan_t **scpp, uint32_t flags)
/*
* 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 @@ sysevent_evc_unbind(evchan_t *scp)
* 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 @@ sysevent_evc_unbind(evchan_t *scp)
(void) close(EV_FD(scp));
(void) mutex_destroy(EV_LOCK(scp));
free(scp);
+
+ return (0);
}
/*
@@ -287,6 +324,13 @@ door_upcall(void *cookie, char *args, size_t alen,
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 @@ door_upcall(void *cookie, char *args, size_t alen,
(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 @@ sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class,
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 @@ sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class,
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 @@ sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class,
(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 @@ sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class,
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(evchan_t *scp, const char *sid, const char *class,
}
/*
- * sysevent_evc_unsubscribe - Unsubscribe from an existing event channel
+ * 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
+ */
+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 @@ sysevent_evc_unsubscribe(evchan_t *scp, const char *sid)
uargs.sid.len = strlen(sid) + 1;
}
+ if (will_deadlock(scp))
+ return (errno = EDEADLK);
+
(void) mutex_lock(EV_LOCK(scp));
/*
@@ -444,31 +726,50 @@ sysevent_evc_unsubscribe(evchan_t *scp, const char *sid)
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;
+ subp = subp->evsub_next;
+
+ /* If door_xcreate was applied we can clean up */
+ if (tofree->evsub_attr)
+ kill_door_servers(tofree);
- tofree = subp->evsub_next;
- subp->evsub_next = tofree->evsub_next;
(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);
}
/*
diff --git a/usr/src/lib/libsysevent/libsysevent.c b/usr/src/lib/libsysevent/libsysevent.c
index dc2ebe9858..23cecfd7ad 100644
--- a/usr/src/lib/libsysevent/libsysevent.c
+++ b/usr/src/lib/libsysevent/libsysevent.c
@@ -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 @@ sysevent_alloc(char *class, int class_sz, char *subclass, int subclass_sz,
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 @@ sysevent_post_event(char *class, char *subclass, char *vendor, char *pub_name,
}
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 @@ se_print(FILE *fp, sysevent_t *ev)
(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 @@ struct reg_args {
* 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 @@ dealloc_subscribers(sysevent_handle_t *shp)
}
}
+/*ARGSUSED*/
static int
alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag)
{
@@ -1470,6 +1469,7 @@ create_failed:
* 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 @@ cache_update_service(void *cookie, char *args, size_t alen,
goto return_from_door;
}
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
rargs = (struct reg_args *)args;
shp = (sysevent_handle_t *)cookie;
@@ -1833,8 +1834,8 @@ sysevent_open_channel(const char *channel)
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 @@ sysevent_bind_subscriber(sysevent_handle_t *shp,
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 @@ sysevent_bind_subscriber(sysevent_handle_t *shp,
/* 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;
}
diff --git a/usr/src/lib/libsysevent/libsysevent_impl.h b/usr/src/lib/libsysevent/libsysevent_impl.h
index 7d02359212..edd6988169 100644
--- a/usr/src/lib/libsysevent/libsysevent_impl.h
+++ b/usr/src/lib/libsysevent/libsysevent_impl.h
@@ -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 @@ typedef struct evchan_impl_handle {
#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 @@ struct evchan_subscriber {
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))
diff --git a/usr/src/lib/libsysevent/llib-lsysevent b/usr/src/lib/libsysevent/llib-lsysevent
index 848135ec67..a0cc48b012 100644
--- a/usr/src/lib/libsysevent/llib-lsysevent
+++ b/usr/src/lib/libsysevent/llib-lsysevent
@@ -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 @@ void se_print(FILE *fp, sysevent_t *ev);
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 @@ int sysevent_evc_subscribe(evchan_t *scp, const char *sid,
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);
+
diff --git a/usr/src/lib/libsysevent/mapfile-vers b/usr/src/lib/libsysevent/mapfile-vers
index e9fb12a36d..7e4107db31 100644
--- a/usr/src/lib/libsysevent/mapfile-vers
+++ b/usr/src/lib/libsysevent/mapfile-vers
@@ -84,6 +84,7 @@ SUNWprivate_1.1 {
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 @@ SUNWprivate_1.1 {
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:
*;
};
diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c
index 88c2c2c5a1..d483088ccd 100644
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c
@@ -6060,7 +6060,7 @@ zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
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 @@ zonecfg_notify_unbind(void *handle)
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.
diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_com b/usr/src/pkgdefs/SUNWfmd/prototype_com
index 65ea84e8fd..40e3ed0668 100644
--- a/usr/src/pkgdefs/SUNWfmd/prototype_com
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_com
@@ -34,6 +34,7 @@ d none usr/include/fm 755 root bin
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.conf 644 root bin
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 @@ f none usr/lib/fm/libfmd_snmp.so.1 755 root bin
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
diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_i386 b/usr/src/pkgdefs/SUNWfmd/prototype_i386
index 6acf321c3f..773e0f65f8 100644
--- a/usr/src/pkgdefs/SUNWfmd/prototype_i386
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_i386
@@ -33,6 +33,8 @@ f none usr/lib/fm/amd64/libdiagcode.so.1 755 root bin
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_adm.ln 644 root bin
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
diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_sparc b/usr/src/pkgdefs/SUNWfmd/prototype_sparc
index 4c2b73f2d3..f932a5f131 100644
--- a/usr/src/pkgdefs/SUNWfmd/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_sparc
@@ -56,6 +56,8 @@ f none usr/lib/fm/sparcv9/libdiagcode.so.1 755 root bin
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/llib-lldom.ln 644 root bin
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
diff --git a/usr/src/uts/common/io/bofi.c b/usr/src/uts/common/io/bofi.c
index 275362dd51..80b69bd07b 100644
--- a/usr/src/uts/common/io/bofi.c
+++ b/usr/src/uts/common/io/bofi.c
@@ -784,7 +784,7 @@ bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
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);
diff --git a/usr/src/uts/common/os/evchannels.c b/usr/src/uts/common/os/evchannels.c
index a25ef4fa65..9ae0565244 100644
--- a/usr/src/uts/common/os/evchannels.c
+++ b/usr/src/uts/common/os/evchannels.c
@@ -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 @@ evch_zonefree(zoneid_t zoneid, void *arg)
*/
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 @@ evch_namecmp(evch_dlelem_t *ep, char *s)
}
/*
+ * 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 @@ evch_chbind(const char *chnam, evch_bind_t **scpp, uint32_t flags)
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 @@ evch_chunbind(evch_bind_t *bp)
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 @@ evch_chunbind(evch_bind_t *bp)
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 @@ evch_chsubscribe(evch_bind_t *bp, int dtype, const char *sid, const char *class,
*/
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 @@ sysevent_evc_bind(const char *ch_name, evchan_t **scpp, uint32_t flags)
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 @@ sysevent_evc_unbind(evchan_t *scp)
ASSERT(scp != NULL);
evch_chunsubscribe(bp, NULL, 0);
evch_chunbind(bp);
+
+ return (0);
}
int
@@ -1784,7 +1855,7 @@ sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class,
(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 @@ sysevent_evc_unsubscribe(evchan_t *scp, const char *sid)
sid = NULL;
}
evch_chunsubscribe((evch_bind_t *)scp, sid, 0);
+
+ return (0);
}
/*
diff --git a/usr/src/uts/common/os/fm.c b/usr/src/uts/common/os/fm.c
index c5ad2c3991..7dec9d8b91 100644
--- a/usr/src/uts/common/os/fm.c
+++ b/usr/src/uts/common/os/fm.c
@@ -517,10 +517,10 @@ fm_ereport_post(nvlist_t *ereport, int evc_flag)
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);
}
/*
diff --git a/usr/src/uts/common/sys/door.h b/usr/src/uts/common/sys/door.h
index e45386270d..7d04847864 100644
--- a/usr/src/uts/common/sys/door.h
+++ b/usr/src/uts/common/sys/door.h
@@ -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 @@ typedef struct __door_handle *door_handle_t; /* opaque kernel door handle */
/* 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 */
diff --git a/usr/src/uts/common/sys/sysevent.h b/usr/src/uts/common/sys/sysevent.h
index 0a61e41de8..44b5d069fb 100644
--- a/usr/src/uts/common/sys/sysevent.h
+++ b/usr/src/uts/common/sys/sysevent.h
@@ -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 @@ typedef struct sysevent_value {
#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 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_SUB_KEEP 0x0001
#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 @@ typedef struct sysevent_value {
#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, ...);
-#ifdef _KERNEL
+#ifndef _KERNEL
+
+/*
+ * Userland-only event channel interfaces
+ */
+
+#include <door.h>
+
+typedef struct sysevent_subattr sysevent_subattr_t;
+
+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 *);
-
-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 int log_sysevent(sysevent_t *, int, sysevent_id_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 */
diff --git a/usr/src/uts/common/sys/sysevent_impl.h b/usr/src/uts/common/sys/sysevent_impl.h
index 11115c8f2d..215862fbdd 100644
--- a/usr/src/uts/common/sys/sysevent_impl.h
+++ b/usr/src/uts/common/sys/sysevent_impl.h
@@ -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 @@ typedef struct {
/*
* 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
diff --git a/usr/src/uts/sun4v/io/vlds.c b/usr/src/uts/sun4v/io/vlds.c
index dc363293d1..4eedeee56b 100644
--- a/usr/src/uts/sun4v/io/vlds.c
+++ b/usr/src/uts/sun4v/io/vlds.c
@@ -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 @@ vlds_close(dev_t dev, int flag, int otyp, cred_t *credp)
}
if (sp->evchan) {
- sysevent_evc_unbind(sp->evchan);
+ (void) sysevent_evc_unbind(sp->evchan);
sp->evchan = NULL;
}