protocol.c revision 2c65c8b07fc9eb4a059c4c47b7d637cd6905909e
/*
* 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
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* protocol.c - protocols between graph engine and restarters
*
* The graph engine uses restarter_protocol_send_event() to send a
* restarter_event_type_t to the restarter. For delegated restarters,
* this is published on the GPEC queue for the restarter, which can
* then be consumed by the librestart interfaces. For services managed
* by svc.startd, the event is stored on the local restarter_queue list,
* where it can be dequeued by the restarter.
*
* The svc.startd restarter uses graph_protocol_send_event() to send
* a graph_event_type_t to the graph engine when an instance's states are
* updated.
*
* The graph engine uses restarter_protocol_init_delegate() to
* register its interest in a particular delegated restarter's instance
* state events. The state_cb() registered on the event channel then
* invokes graph_protocol_send_event() to communicate the update to
* the graph engine.
*/
#include <assert.h>
#include <libintl.h>
#include <libsysevent.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <libuutil.h>
#include <librestart.h>
#include <librestart_priv.h>
#include "protocol.h"
#include "startd.h"
/* Local event queue structures. */
typedef struct graph_protocol_event_queue {
typedef struct restarter_protocol_event_queue {
static graph_protocol_event_queue_t *graph_queue;
void
{
"graph_protocol_events", sizeof (graph_protocol_event_t),
}
/*
* "data" will be freed by the consumer
*/
static void
{
e = startd_zalloc(sizeof (graph_protocol_event_t));
e->gpe_inst_sz = size;
}
uu_die("failed to enqueue graph event (%s: %s)\n",
}
void
{
(void) pthread_mutex_destroy(&e->gpe_lock);
startd_free(e, sizeof (graph_protocol_event_t));
}
/*
* graph_protocol_event_t *graph_event_dequeue()
* The caller must hold gu_lock, and is expected to be a single thread.
* It is allowed to utilize graph_event_requeue() and abort processing
* on the event. If graph_event_requeue() is not called, the caller is
* expected to call graph_event_release() when finished.
*/
{
if (e == NULL) {
return (NULL);
}
return (e);
}
/*
* void graph_event_requeue()
* Requeue the event back at the head of the queue.
*/
void
{
uu_die("failed to requeue graph event (%s: %s)\n",
}
void
{
}
void
{
"restarter_protocol_events", sizeof (restarter_protocol_event_t),
sizeof (restarter_protocol_event_queue_t));
}
/*
* void restarter_event_enqueue()
* Enqueue a restarter event.
*/
static void
{
int r;
/* Allocate and populate the event structure. */
e = startd_zalloc(sizeof (restarter_protocol_event_t));
assert(r == 0);
}
void
{
startd_free(e, sizeof (restarter_protocol_event_t));
}
/*
* restarter_protocol_event_t *restarter_event_dequeue()
* Dequeue a restarter protocol event. The caller is expected to be
* a single thread. It is allowed to utilize restarter_event_requeue()
* and abort processing on the event. The caller is expected to call
* restarter_event_release() when finished.
*/
{
if (e == NULL) {
return (NULL);
}
return (e);
}
static int
{
char *instance_name;
int state, next_state;
char str_state[MAX_SCF_STATE_STRING_SZ];
int err;
/*
* Might fail due to a bad event or a lack of memory. Try
* the callback again to see if it goes better the next time.
*/
return (EAGAIN);
&state) != 0) ||
&next_state) != 0) ||
&instance_name) != 0))
states);
sizeof (str_next_state));
return (0);
}
evchan_t *
{
/* master restarter -- nothing to do */
return (NULL);
fmri);
RESTARTER_CHANNEL_DELEGATE)) == NULL ||
RESTARTER_CHANNEL_MASTER)) == NULL ||
uu_die("Allocation failure\n");
EVCH_CREAT|EVCH_HOLD_PEND) != 0)
uu_die("%s: sysevent_evc_bind failed: %s\n",
EVCH_CREAT|EVCH_HOLD_PEND) != 0)
uu_die("%s: sysevent_evc_bind failed: %s\n",
"%s: Bound to channel %s (delegate), %s (master)\n", fmri,
uu_die("%s: Failed to subscribe to channel %s with "
"subscriber id %s: %s\n", fmri,
"%s: Subscribed to channel %s with subscriber id %s\n", fmri,
master_channel_name, "svc.startd");
return (delegate_channel);
}
void
{
int ret;
/*
* If the service is managed by the master restarter,
* queue the event locally.
*/
return;
}
/*
* Otherwise, send the event to the delegate.
*/
uu_die("Allocation failure\n");
switch (ret) {
case ENOSPC:
"Delegate may not be running.\n",
break;
default:
}
}
if (event != RESTARTER_EVENT_TYPE_ADD_INSTANCE) {
/*
* Not relevant for graph loading.
*/
return;
}
/*
* For the purposes of loading state after interruption, this is
* sufficient, as svc.startd(1M) won't receive events on the contracts
* associated with each delegate.
*/
if (--st->st_load_instances == 0)
}