evchannels.c revision f6e214c7418f43af38bd8c3a557e3d0a1d311cfa
/*
* 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
* 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
*/
/*
*/
/*
* This file contains the source of the general purpose event channel extension
* to the sysevent framework. This implementation is made up mainly of four
* layers of functionality: the event queues (evch_evq_*()), the handling of
* channels (evch_ch*()), the kernel interface (sysevent_evc_*()) and the
* interface for the sysevent pseudo driver (evch_usr*()).
* Libsysevent.so uses the pseudo driver sysevent's ioctl to access the event
* channel extensions. The driver in turn uses the evch_usr*() functions below.
*
* The interfaces for user land and kernel are declared in sys/sysevent.h
* Internal data structures for event channels are defined in
*
* The basic data structure for an event channel is of type evch_chan_t.
* All channels are maintained by a list named evch_list. The list head
* is of type evch_dlist_t.
*/
#include <sys/sysevent.h>
#include <sys/sysevent_impl.h>
#include <sys/sysmacros.h>
/* Back-off delay for door_ki_upcall */
#define EVCH_MIN_PAUSE 8
#define EVCH_MAX_PAUSE 128
#define CH_HOLD_PEND 1
#define CH_HOLD_PEND_INDEF 2
struct evch_globals {
};
/* Variables used by event channel routines */
static int evq_initcomplete = 0;
static zone_key_t evch_zone_key;
static uint32_t evch_channels_max;
static uint32_t evch_events_max;
static void evch_evq_destroy(evch_eventq_t *);
/*
* List handling. These functions handle a doubly linked list. The list has
* to be protected by the calling functions. evch_dlist_t is the list head.
* Every node of the list has to put a evch_dlelem_t data type in its data
* structure as its first element.
*
* evch_dl_init - Initialize list head
* evch_dl_fini - Terminate list handling
* evch_dl_is_init - Returns one if list is initialized
* evch_dl_add - Add element to end of list
* evch_dl_del - Remove given element from list
* evch_dl_search - Lookup element in list
* evch_dl_getnum - Get number of elements in list
* evch_dl_next - Get next elements of list
*/
static void
{
}
/*
* Assumes that list is empty.
*/
static void
{
}
static int
{
}
/*
* Add an element at the end of the list.
*/
static void
{
}
/*
* Remove arbitrary element out of dlist.
*/
static void
{
}
/*
* Search an element in a list. Caller provides comparison callback function.
*/
static evch_dlelem_t *
{
evch_dlelem_t *p;
if (cmp(p, s) == 0) {
return (p);
}
}
return (NULL);
}
/*
* Return number of elements in the list.
*/
static int
{
}
/*
* Find next element of a evch_dlist_t list. Find first element if el == NULL.
* Returns NULL if end of list is reached.
*/
static void *
{
return (NULL);
}
}
return (NULL);
}
return ((void *)ep);
}
/*
* Queue handling routines. Mutexes have to be entered previously.
*
* evch_q_init - Initialize queue head
* evch_q_in - Put element into queue
* evch_q_out - Get element out of queue
* evch_q_next - Iterate over the elements of a queue
*/
static void
{
q->sq_tail = (evch_qelem_t *)q;
q->sq_count = 0;
q->sq_highwm = 0;
}
/*
* Put element into the queue q
*/
static void
{
q->sq_count++;
}
}
/*
* Returns NULL if queue is empty.
*/
static evch_qelem_t *
{
q->sq_count--;
q->sq_tail = (evch_qelem_t *)q;
}
}
return (el);
}
/*
* Returns element after *el or first if el == NULL. NULL is returned
* if queue is empty or *el points to the last element in the queue.
*/
static evch_qelem_t *
{
return (q->sq_head);
}
/*
* Event queue handling functions. An event queue is the basic building block
* of an event channel. One event queue makes up the publisher-side event queue.
* Further event queues build the per-subscriber queues of an event channel.
* Each queue is associated an event delivery thread.
* These functions support a two-step initialization. First step, when kernel
* memory is ready and second when threads are ready.
* Events consist of an administrating evch_gevent_t structure with the event
* data appended as variable length payload.
* The internal interface functions for the event queue handling are:
*
* evch_evq_create - create an event queue
* evch_evq_thrcreate - create thread for an event queue.
* evch_evq_destroy - delete an event queue
* evch_evq_sub - Subscribe to event delivery from an event queue
* evch_evq_unsub - Unsubscribe
* evch_evq_pub - Post an event into an event queue
* evch_evq_stop - Put delivery thread on hold
* evch_evq_continue - Resume event delivery thread
* evch_evq_status - Return status of delivery thread, running or on hold
* evch_evq_evzalloc - Allocate an event structure
* evch_evq_evfree - Free an event structure
* evch_evq_evadd_dest - Add a destructor function to an event structure
* evch_evq_evnext - Iterate over events non-destructive
*/
/*ARGSUSED*/
static void *
{
struct evch_globals *eg;
return (eg);
}
/*ARGSUSED*/
static void
{
/*
* Keep picking the head element off the list until there are no
* more.
*/
/*
* Since all processes are gone, all bindings should be gone,
* and only channels with SUB_KEEP subscribers should remain.
*/
/* Forcibly unsubscribe each remaining subscription */
/*
* We should only be tearing down persistent
* subscribers at this point, since all processes
* from this zone are gone.
*/
/*
* Disconnect subscriber queue from main event queue.
*/
/* Destruct per subscriber queue */
/*
* Eliminate the subscriber data from channel list.
*/
}
/* Channel must now have no subscribers */
/* Just like unbind */
}
/* all channels should now be gone */
}
/*
* Frees evch_gevent_t structure including the payload, if the reference count
* drops to or below zero. Below zero happens when the event is freed
* without beeing queued into a queue.
*/
static void
{
if (refcnt <= 0) {
evp->ge_dstcookie);
}
}
}
/*
* Deliver is called for every subscription to the current event
* It calls the registered filter function and then the registered delivery
* callback routine. Returns 0 on success. The callback routine returns
* EVQ_AGAIN or EVQ_SLEEP in case the event could not be delivered.
*/
static int
{
int res = EVQ_DELIVER;
}
if (res == EVQ_DELIVER) {
}
return (0);
}
/*
* Holds event delivery in case of eq_holdmode set or in case the
* event queue is empty. Mutex must be held when called.
* Wakes up a thread waiting for the delivery thread reaching the hold mode.
*/
static void
{
if (eqp->eq_tabortflag == 0) {
do {
if (eqp->eq_holdmode) {
}
} while (eqp->eq_holdmode);
}
}
/*
* Event delivery thread. Enumerates all subscribers and calls evch_deliver()
* for each one.
*/
static void
{
int res;
int deltime;
int repeatcount;
char thnam[32];
while (eqp->eq_tabortflag == 0) {
/* Filter and deliver event to all subscribers */
eqp->eq_dactive = 0;
switch (res) {
case EVQ_SLEEP:
/*
* Wait for subscriber to return.
*/
if (eqp->eq_tabortflag) {
break;
}
continue;
case EVQ_AGAIN:
deltime =
&eqp->eq_queuemx);
if (repeatcount-- > 0) {
continue;
}
break;
}
if (eqp->eq_tabortflag) {
break;
}
}
/* Free event data and queue element */
}
/* Wait for next event or end of hold mode if set */
}
thread_exit();
}
/*
* Create the event delivery thread for an existing event queue.
*/
static void
{
}
/*
* Create event queue.
*/
static evch_eventq_t *
{
evch_eventq_t *p;
/* Allocate and initialize event queue descriptor */
evch_q_init(&p->eq_eventq);
evch_dl_init(&p->eq_subscr);
/* Create delivery thread */
if (evq_initcomplete) {
}
return (p);
}
/*
* Destroy an event queue. All subscribers have to be unsubscribed prior to
* this call.
*/
static void
{
/* Kill delivery thread */
eqp->eq_holdmode = 0;
}
/* Get rid of stale events in the event queue */
}
/* Wrap up event queue structure */
/* Free descriptor structure */
}
/*
* Subscribe to an event queue. Every subscriber provides a filter callback
* routine and an event delivery callback routine.
*/
static evch_evqsub_t *
{
/* Initialize subscriber structure */
/* Add subscription to queue */
return (sp);
}
/*
* Unsubscribe from an event queue.
*/
static void
{
/* Wait if delivery is just in progress */
if (eqp->eq_dactive) {
}
}
/*
* Publish an event. Returns 0 on success and -1 if memory alloc failed.
*/
static int
{
size = sizeof (evch_qelem_t);
if (flags & EVCH_TRYHARD) {
} else {
KM_NOSLEEP : KM_SLEEP);
}
return (-1);
}
/* Wakeup delivery thread */
return (0);
}
/*
* Enter hold mode of an event queue. Event delivery thread stops event
* handling after delivery of current event (if any).
*/
static void
{
if (evq_initcomplete) {
}
}
/*
* Continue event delivery.
*/
static void
{
eqp->eq_holdmode = 0;
}
/*
* Returns status of delivery thread. 0 if running and 1 if on hold.
*/
static int
{
return (eqp->eq_holdmode);
}
/*
* Add a destructor function to an event structure.
*/
static void
{
}
/*
* Allocate evch_gevent_t structure. Return address of payload offset of
* evch_gevent_t. If EVCH_TRYHARD allocation is requested, we use
* kmem_alloc_tryhard to alloc memory of at least paylsize bytes.
*
* If either memory allocation is unsuccessful, we return NULL.
*/
static void *
{
if (flag & EVCH_TRYHARD) {
} else {
KM_SLEEP);
}
if (evp) {
return (&evp->ge_payload);
}
return (evp);
}
/*
* Free event structure. Argument ev is address of payload offset.
*/
static void
evch_evq_evfree(void *ev)
{
}
/*
* Iterate over all events in the event queue. Begin with an event
* which is currently being delivered. No mutexes are grabbed and no
* resources allocated so that this function can be called in panic
* context too. This function has to be called with ev == NULL initially.
* Actually argument ev is only a flag. Internally the member eq_nextev
* is used to determine the next event. But ev allows for the convenient
* use like
* ev = NULL;
* while ((ev = evch_evq_evnext(evp, ev)) != NULL) ...
*/
static void *
{
}
return (NULL);
}
/*
* Channel handling functions. First some support functions. Functions belonging
* to the channel handling interface start with evch_ch. The following functions
* make up the channel handling internal interfaces:
*
* evch_chinit - Initialize channel handling
* evch_chinitthr - Second step init: initialize threads
* evch_chbind - Bind to a channel
* evch_chunbind - Unbind from a channel
* evch_chsubscribe - Subscribe to a sysevent class
* evch_chunsubscribe - Unsubscribe
* evch_chpublish - Publish an event
* evch_chgetnames - Get names of all channels
* evch_chgetchdata - Get data of a channel
* evch_chrdevent_init - Init event q traversal
* evch_chgetnextev - Read out events queued for a subscriber
* evch_chrdevent_fini - Finish event q traversal
*/
/*
* Compare channel name. Used for evch_dl_search to find a channel with the
* name s.
*/
static int
{
}
/*
* 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
{
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') {
return (1);
}
return (0);
}
} while (c == *class++);
return (0);
}
/*
* Sysevent filter callback routine. Enables event delivery only if it matches
* the event class pattern string given by parameter cookie.
*/
static int
{
return (EVQ_DELIVER);
return (EVQ_IGNORE);
}
/*
* Callback routine to propagate the event into a per subscriber queue.
*/
static int
{
return (EVQ_CONT);
}
/*
* Call kernel callback routine for sysevent kernel delivery.
*/
static int
{
}
/*
* Door upcall for user land sysevent delivery.
*/
static int
{
int error;
int nticks = EVCH_MIN_PAUSE;
int retry = 20;
/* Initialize door args */
for (;;) {
break;
}
switch (error) {
case EAGAIN:
/* Cannot deliver event - process may be forking */
nticks <<= 1;
if (nticks > EVCH_MAX_PAUSE) {
}
if (retry-- <= 0) {
"door_ki_upcall error EAGAIN\n");
return (EVQ_CONT);
}
break;
case EINTR:
case EBADF:
/* Process died */
return (EVQ_SLEEP);
default:
"event delivery thread: door_ki_upcall error %d\n",
error);
return (EVQ_CONT);
}
}
return (EVQ_AGAIN);
}
return (EVQ_CONT);
}
/*
* Callback routine for evch_dl_search() to compare subscriber id's. Used by
* evch_subscribe() and evch_chrdevent_init().
*/
static int
{
}
/*
* Callback routine for evch_dl_search() to find a subscriber with EVCH_SUB_DUMP
* set (indicated by sub->sd_dump != 0). Used by evch_chrdevent_init() and
* evch_subscribe(). Needs to returns 0 if subscriber with sd_dump set is
* found.
*/
/*ARGSUSED1*/
static int
{
}
/*
* Event destructor function. Used to maintain the number of events per channel.
*/
/*ARGSUSED*/
static void
{
chp->ch_nevents--;
}
/*
* Integer square root according to Newton's iteration.
*/
static uint32_t
{
uint64_t x = n >> 1;
if (n < 4) {
return (lowval[n]);
}
while (xn < x) {
x = xn;
xn = (x + n / x) / 2;
}
}
/*
* First step sysevent channel initialization. Called when kernel memory
* allocator is initialized.
*/
static void
{
size_t k;
/*
* Calculate limits: max no of channels and max no of events per
* channel. The smallest machine with 128 MByte will allow for
* >= 8 channels and an upper limit of 2048 events per channel.
* The event limit is the number of channels times 256 (hence
* the shift factor of 8). These number where selected arbitrarily.
*/
k = kmem_maxavail() >> 20;
/*
* Will trigger creation of the global zone's evch state.
*/
}
/*
* Second step sysevent channel initialization. Called when threads are ready.
*/
static void
{
struct evch_globals *eg;
/*
* We're early enough in boot that we know that only the global
* zone exists; we only need to initialize its threads.
*/
}
}
evq_initcomplete = 1;
}
/*
* Sysevent channel bind. Create channel and allocate binding structure.
*/
static int
{
struct evch_globals *eg;
evch_chan_t *p;
char *chn;
int rv;
/* Create channel if it does not exist */
return (EINVAL);
}
if (flags & EVCH_CREAT) {
return (ENOMEM);
}
/* Allocate and initialize channel descriptor */
p->ch_namelen = namlen;
p->ch_queue = evch_evq_create();
evch_dl_init(&p->ch_subscr);
if (evq_initcomplete) {
}
p->ch_maxbinds = evch_bindings_max;
p->ch_ctime = gethrestime_sec();
if (flags & EVCH_HOLD_PEND_INDEF)
else
p->ch_holdpend = CH_HOLD_PEND;
evch_evq_stop(p->ch_queue);
}
/* Put new descriptor into channel list */
} else {
return (ENOENT);
}
}
/* Check for max binds and create binding */
mutex_enter(&p->ch_mutex);
if (p->ch_bindings >= p->ch_maxbinds) {
/*
* No need to destroy the channel because this call did not
* create it. Other bindings will be present if ch_maxbinds
* is exceeded.
*/
goto errorexit;
}
bp->bd_channel = p;
p->ch_bindings++;
rv = 0;
mutex_exit(&p->ch_mutex);
return (rv);
}
/*
* Unbind: Free bind structure. Remove channel if last binding was freed.
*/
static void
{
struct evch_globals *eg;
chp->ch_bindings--;
/*
* 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.
*/
if (chp->ch_propnvl)
} else
}
static int
wildcard_count(const char *class)
{
int count = 0;
char c;
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
* dinfo gives the call back routine address or the door handle.
*/
static int
{
int (*delivfkt)();
int clblen = 0;
char *subid;
int subidblen;
/*
* Check if only known flags are set.
*/
return (EINVAL);
/*
* Enforce a limit on the number of wildcards allowed in the class
* subscription string (limits recursion in pattern matching).
*/
return (EINVAL);
/*
* Check if we have already a subscription with that name and if we
* have to reconnect the subscriber to a persistent subscription.
*/
int error = 0;
/*
* Subscription with the name on hold, reconnect to
* existing queue.
*/
} else {
/* Subscriber with given name already exists */
}
return (error);
}
return (ENOMEM);
}
/*
* Subscription with EVCH_SUB_DUMP flagged already exists.
* Only one subscription with EVCH_SUB_DUMP possible. Return
* error.
*/
return (EINVAL);
}
}
/* Create per subscriber queue */
/* Subscribe to subscriber queue */
if (dtype == EVCH_DELKERN) {
} else {
}
/* Connect per subscriber queue to main event queue */
evch_subq_deliver, (void *)sdp);
/* Add subscription to binding */
/* Add subscription to channel */
/* Let main event queue run in case of HOLDPEND */
}
return (0);
}
/*
* If flag == EVCH_SUB_KEEP only non-persistent subscriptions are deleted.
* When sid == NULL all subscriptions except the ones with EVCH_SUB_KEEP set
* are removed.
*/
static void
{
if (chp->ch_holdpend) {
}
/*
* Disconnect subscriber queue from main event
* queue.
*/
/* Destruct per subscriber queue */
/*
* Eliminate the subscriber data from channel
* list.
*/
}
if (prev) {
} else {
}
} else {
/*
* EVCH_SUB_KEEP case
*/
}
}
break;
}
} else {
}
}
/*
* Continue dispatch thread except if no subscribers are present
* in HOLDPEND mode.
*/
}
}
/*
* Publish an event. Returns zero on success and an error code else.
*/
static int
{
if (!(flags & EVCH_QWAIT)) {
return (EAGAIN);
} else {
/* Got Signal, return EINTR */
return (EINTR);
}
}
}
}
chp->ch_nevents++;
/*
* Add the destructor function to the event structure, now that the
* event is accounted for. The only task of the descructor is to
* decrement the channel event count. The evq_*() routines (including
* the event delivery thread) do not have knowledge of the channel
* data. So the anonymous destructor handles the channel data for it.
*/
}
/*
* Fills a buffer consecutive with the names of all available channels.
* Returns the length of all name strings or -1 if buffer size was unsufficient.
*/
static int
{
struct evch_globals *eg;
int len = 0;
return (-1);
}
}
addr[0] = 0;
return (len + 1);
}
/*
* Fills the data of one channel and all subscribers of that channel into
* a buffer. Returns -1 if the channel name is invalid and 0 on buffer overflow.
*/
static int
{
struct evch_globals *eg;
char *cpaddr;
int bufmax;
int buflen;
int chdlen;
int idlen;
int len;
chname);
return (-1);
}
return (0);
}
p->cd_version = 0;
p->cd_suboffs = chdlen;
p->cd_perms = 0;
p->cd_limev = evch_events_max;
buflen = 0;
sdp->sd_clnsize);
return (0);
}
if (sdp->sd_classname) {
sdp->sd_clnsize);
} else {
}
}
}
static void
{
if (chp->ch_propnvl)
chp->ch_propnvlgen++;
}
static int
{
int rc = 0;
else
if (genp)
if (rc != 0)
return (rc);
}
/*
* Init iteration of all events of a channel. This function creates a new
* event queue and puts all events from the channel into that queue.
* Subsequent calls to evch_chgetnextev will deliver the events from that
* queue. Only one thread per channel is allowed to read through the events.
* Returns 0 on success and 1 if there is already someone reading the
* events.
* If argument subid == NULL, we look for a subscriber which has
* flag EVCH_SUB_DUMP set.
*/
/*
* Static variables that are used to traverse events of a channel in panic case.
*/
static evch_chan_t *evch_chan;
static evch_eventq_t *evch_subq;
static sysevent_impl_t *evch_curev;
static evchanq_t *
{
void *ev;
int pmqstat; /* Prev status of main queue */
int psqstat; /* Prev status of subscriber queue */
evch_curev = NULL;
}
return (NULL);
}
/*
* Stop main event queue and subscriber queue if not already
* in stop mode.
*/
if (pmqstat == 0)
if (psqstat == 0)
}
/*
* Create event queue to make a snapshot of all events in the
* channel.
*/
/*
* Make a snapshot of the subscriber queue and the main event queue.
*/
}
}
}
/*
* Restart main and subscriber queue if previously stopped
*/
if (pmqstat == 0)
return (snp);
}
/*
* Free all resources of the event queue snapshot. In case of panic
* context snp must be NULL and no resources need to be free'ed.
*/
static void
{
}
}
/*
* Get address of next event from an event channel.
* This function might be called in a panic context. In that case
* no resources will be allocated and no locks grabbed.
* In normal operation context a snapshot of the event queues of the
* specified event channel will be taken.
*/
static sysevent_impl_t *
{
return (NULL);
/*
* We have a subscriber queue. Traverse this queue
* first.
*/
if ((evch_curev = (sysevent_impl_t *)
return (evch_curev);
} else {
/*
* All subscriber events traversed. evch_subq
* == NULL indicates to take the main event
* queue now.
*/
}
}
/*
* Traverse the main event queue.
*/
if ((evch_curev = (sysevent_impl_t *)
NULL) {
}
return (evch_curev);
}
}
/*
* subscribe/unsubscribe and publish to event channels. It consists of the
* following functions:
*
* sysevent_evc_bind - Bind to a channel. Create a channel if required
* sysevent_evc_unbind - Unbind from a channel. Destroy ch. if last unbind
* sysevent_evc_subscribe - Subscribe to events from a channel
* sysevent_evc_unsubscribe - Unsubscribe from an event class
* sysevent_evc_publish - Publish an event to an event channel
* sysevent_evc_control - Various control operation on event channel
* sysevent_evc_setpropnvl - Set channel property nvlist
* sysevent_evc_getpropnvl - Get channel property nvlist
*
* The function below are for evaluating a sysevent:
*
* sysevent_get_class_name - Get pointer to event class string
* sysevent_get_subclass_name - Get pointer to event subclass string
* sysevent_get_seq - Get unique event sequence number
* sysevent_get_time - Get hrestime of event publish
* sysevent_get_size - Get size of event structure
* sysevent_get_pub - Get publisher string
* sysevent_get_attr_list - Get copy of attribute list
*
* The following interfaces represent stability level project privat
* and allow to save the events of an event channel even in a panic case.
*
* sysevent_evc_walk_init - Take a snapshot of the events in a channel
* sysevent_evc_walk_step - Read next event from snapshot
* sysevent_evc_walk_fini - Free resources from event channel snapshot
* sysevent_evc_event_attr - Get event payload address and size
*/
/*
* allocate sysevent structure with optional space for attributes
*/
static sysevent_impl_t *
{
int payload_sz;
int class_sz, subclass_sz;
/*
* Calculate and reserve space for the class, subclass and
* publisher strings in the event buffer
*/
/* String sizes must be 64-bit aligned in the event buffer */
/*
* Calculate payload size. Consider the space needed for alignment
* and subtract the size of the uint64_t placeholder variables of
* sysevent_impl_t.
*/
(aligned_subclass_sz - sizeof (uint64_t)) +
atsz;
/*
* Allocate event buffer plus additional payload overhead
*/
return (NULL);
}
/* Initialize the event buffer data */
return (ev);
}
/*
* Initialize event channel handling queues.
*/
void
{
evch_chinit();
}
/*
* Second initialization step: create threads, if event channels are already
* created
*/
void
{
}
int
{
}
int
{
return (0);
}
int
{
return (EINVAL);
}
}
}
int
{
}
return (0);
}
/*
* Publish kernel event. Returns 0 on success, error code else.
* Optional attribute data is packed into the event structure.
*/
int
{
char pub[MAX_PUB_LEN];
int pub_sz; /* includes terminating 0 */
int km_flags;
int err;
EVCH_QWAIT)) == 0);
km_flags == EVCH_TRYHARD);
if (pub_sz > MAX_PUB_LEN)
return (EINVAL);
return (err);
}
}
return (ENOMEM);
}
/*
* Pack attributes into event buffer. Event buffer already
* has enough room for the packed nvlist.
*/
if (err != 0) {
return (EINVAL);
}
}
}
int
{
int rc = 0;
return (EINVAL);
}
switch (cmd) {
case EVCH_GET_CHAN_LEN:
break;
case EVCH_SET_CHAN_LEN:
}
break;
case EVCH_GET_CHAN_LEN_MAX:
break;
default:
}
return (rc);
}
int
{
return (ENOMEM);
return (0);
}
int
{
}
/*
* Project private interface to take a snapshot of all events of the
* specified event channel. Argument subscr may be a subscriber id, the empty
* string "", or NULL. The empty string indicates that no subscriber is
* selected, for example if a previous subscriber died. sysevent_evc_walk_next()
* will deliver events from the main event queue in this case. If subscr is
* NULL, the subscriber with the EVCH_SUB_DUMP flag set (subd->sd_dump != 0)
* will be selected.
*
* In panic case this function returns NULL. This is legal. The NULL has
* to be delivered to sysevent_evc_walk_step() and sysevent_evc_walk_fini().
*/
{
return (NULL);
}
/*
* Project private interface to read events from a previously taken
* snapshot (with sysevent_evc_walk_init). In case of panic events
* are retrieved directly from the channel data structures. No resources
* are allocated and no mutexes are grabbed in panic context.
*/
{
}
/*
* Project private interface to free a previously taken snapshot.
*/
void
{
}
/*
* Get address and size of an event payload. Returns NULL when no
* payload present.
*/
char *
{
char *attrp;
}
/*
* sysevent_get_class_name - Get class name string
*/
char *
{
return (SE_CLASS_NAME(ev));
}
/*
* sysevent_get_subclass_name - Get subclass name string
*/
char *
{
return (SE_SUBCLASS_NAME(ev));
}
/*
* sysevent_get_seq - Get event sequence id
*/
{
}
/*
* sysevent_get_time - Get event timestamp
*/
void
{
}
/*
* sysevent_get_size - Get event buffer size
*/
{
}
/*
* sysevent_get_pub - Get publisher name string
*/
char *
{
return (SE_PUB_NAME(ev));
}
/*
* sysevent_get_attr_list - stores address of a copy of the attribute list
* associated with the given sysevent buffer. The list must be freed by the
* caller.
*/
int
{
int error;
return (EINVAL);
}
return (EINVAL);
}
/* unpack nvlist */
return (error);
}
return (0);
}
/*
* Functions called by the sysevent driver for general purpose event channels
*
* evch_usrallocev - Allocate event data structure
* evch_usrfreeev - Free event data structure
* evch_usrpostevent - Publish event
* evch_usrsubscribe - Subscribe (register callback function)
* evch_usrunsubscribe - Unsubscribe
* evch_usrcontrol_set - Set channel properties
* evch_usrcontrol_get - Get channel properties
* evch_usrgetchnames - Get list of channel names
* evch_usrgetchdata - Get data of an event channel
* evch_usrsetpropnvl - Set channel properties nvlist
* evch_usrgetpropnvl - Get channel properties nvlist
*/
evchan_t *
{
}
/*
* Unbind from the channel.
*/
void
{
}
/*
* Allocates log_evch_eventq_t structure but returns the pointer of the embedded
* sysevent_impl_t structure as the opaque sysevent_t * data type
*/
{
}
/*
* Free evch_eventq_t structure
*/
void
{
evch_evq_evfree((void *)ev);
}
/*
* Posts an event to the given channel. The event structure has to be
* allocated by evch_usrallocev(). Returns zero on success and an error
* code else. Attributes have to be packed and included in the event structure.
*
*/
int
{
}
/*
* Subscribe function for user land subscriptions
*/
int
{
int rv;
return (EINVAL);
}
}
return (rv);
}
/*
* Flag can be EVCH_SUB_KEEP or 0. EVCH_SUB_KEEP preserves persistent
* subscribers
*/
void
{
}
/*ARGSUSED*/
int
{
int rc = 0;
switch (cmd) {
case EVCH_SET_CHAN_LEN:
break;
}
break;
default:
}
return (rc);
}
/*ARGSUSED*/
int
{
int rc = 0;
switch (cmd) {
case EVCH_GET_CHAN_LEN:
break;
case EVCH_GET_CHAN_LEN_MAX:
*value = evch_events_max;
break;
default:
}
return (rc);
}
int
{
}
int
{
}
void
{
}
int
{
}