summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os/contract.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/os/contract.c')
-rw-r--r--usr/src/uts/common/os/contract.c166
1 files changed, 153 insertions, 13 deletions
diff --git a/usr/src/uts/common/os/contract.c b/usr/src/uts/common/os/contract.c
index aadfb92e62..6fde3f5714 100644
--- a/usr/src/uts/common/os/contract.c
+++ b/usr/src/uts/common/os/contract.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,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -174,6 +173,8 @@
#include <sys/proc.h>
#include <sys/contract_impl.h>
#include <sys/contract/process_impl.h>
+#include <sys/dditypes.h>
+#include <sys/contract/device_impl.h>
#include <sys/systm.h>
#include <sys/atomic.h>
#include <sys/cmn_err.h>
@@ -181,6 +182,8 @@
#include <sys/policy.h>
#include <sys/zone.h>
#include <sys/task.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
extern rctl_hndl_t rc_project_contract;
@@ -191,6 +194,7 @@ static kmutex_t contract_lock;
int ct_ntypes = CTT_MAXTYPE;
static ct_type_t *ct_types_static[CTT_MAXTYPE];
ct_type_t **ct_types = ct_types_static;
+int ct_debug;
static void cte_queue_create(ct_equeue_t *, ct_listnum_t, int, int);
static void cte_queue_destroy(ct_equeue_t *);
@@ -237,6 +241,7 @@ contract_init(void)
* Initialize contract types.
*/
contract_process_init();
+ contract_device_init();
/*
* Initialize p0/lwp0 contract state.
@@ -310,6 +315,9 @@ contract_ctor(contract_t *ct, ct_type_t *type, ct_template_t *tmpl, void *data,
ct->ct_ev_crit = tmpl->ctmpl_ev_crit;
ct->ct_cookie = tmpl->ctmpl_cookie;
ct->ct_owner = author;
+ ct->ct_ntime.ctm_total = -1;
+ ct->ct_qtime.ctm_total = -1;
+ ct->ct_nevent = NULL;
/*
* Test project.max-contracts.
@@ -570,6 +578,12 @@ contract_abandon(contract_t *ct, proc_t *p, int explicit)
return (0);
}
+int
+contract_newct(contract_t *ct)
+{
+ return (ct->ct_type->ct_type_ops->contop_newct(ct));
+}
+
/*
* contract_adopt
*
@@ -647,11 +661,15 @@ contract_adopt(contract_t *ct, proc_t *p)
* Acknowledges receipt of a critical event.
*/
int
-contract_ack(contract_t *ct, uint64_t evid)
+contract_ack(contract_t *ct, uint64_t evid, int ack)
{
ct_kevent_t *ev;
list_t *queue = &ct->ct_events.ctq_events;
int error = ESRCH;
+ int nego = 0;
+ uint_t evtype;
+
+ ASSERT(ack == CT_ACK || ack == CT_NACK);
mutex_enter(&ct->ct_lock);
mutex_enter(&ct->ct_events.ctq_lock);
@@ -660,9 +678,14 @@ contract_ack(contract_t *ct, uint64_t evid)
*/
for (ev = list_head(queue); ev; ev = list_next(queue, ev)) {
if (ev->cte_id == evid) {
+ if (ev->cte_flags & CTE_NEG)
+ nego = 1;
+ else if (ack == CT_NACK)
+ break;
if ((ev->cte_flags & (CTE_INFO | CTE_ACK)) == 0) {
ev->cte_flags |= CTE_ACK;
ct->ct_evcnt--;
+ evtype = ev->cte_type;
error = 0;
}
break;
@@ -671,9 +694,86 @@ contract_ack(contract_t *ct, uint64_t evid)
mutex_exit(&ct->ct_events.ctq_lock);
mutex_exit(&ct->ct_lock);
+ /*
+ * Not all critical events are negotiation events, however
+ * every negotiation event is a critical event. NEGEND events
+ * are critical events but are not negotiation events
+ */
+ if (error || !nego)
+ return (error);
+
+ if (ack == CT_ACK)
+ error = ct->ct_type->ct_type_ops->contop_ack(ct, evtype, evid);
+ else
+ error = ct->ct_type->ct_type_ops->contop_nack(ct, evtype, evid);
+
return (error);
}
+/*ARGSUSED*/
+int
+contract_ack_inval(contract_t *ct, uint_t evtype, uint64_t evid)
+{
+ cmn_err(CE_PANIC, "contract_ack_inval: unsupported call: ctid: %u",
+ ct->ct_id);
+ return (ENOSYS);
+}
+
+/*ARGSUSED*/
+int
+contract_qack_inval(contract_t *ct, uint_t evtype, uint64_t evid)
+{
+ cmn_err(CE_PANIC, "contract_ack_inval: unsupported call: ctid: %u",
+ ct->ct_id);
+ return (ENOSYS);
+}
+
+/*ARGSUSED*/
+int
+contract_qack_notsup(contract_t *ct, uint_t evtype, uint64_t evid)
+{
+ return (ERANGE);
+}
+
+/*
+ * contract_qack
+ *
+ * Asks that negotiations be extended by another time quantum
+ */
+int
+contract_qack(contract_t *ct, uint64_t evid)
+{
+ ct_kevent_t *ev;
+ list_t *queue = &ct->ct_events.ctq_events;
+ int nego = 0;
+ uint_t evtype;
+
+ mutex_enter(&ct->ct_lock);
+ mutex_enter(&ct->ct_events.ctq_lock);
+
+ for (ev = list_head(queue); ev; ev = list_next(queue, ev)) {
+ if (ev->cte_id == evid) {
+ if ((ev->cte_flags & (CTE_NEG | CTE_ACK)) == CTE_NEG) {
+ evtype = ev->cte_type;
+ nego = 1;
+ }
+ break;
+ }
+ }
+ mutex_exit(&ct->ct_events.ctq_lock);
+ mutex_exit(&ct->ct_lock);
+
+ /*
+ * Only a negotiated event (which is by definition also a critical
+ * event) which has not yet been acknowledged can provide
+ * time quanta to a negotiating owner process.
+ */
+ if (!nego)
+ return (ESRCH);
+
+ return (ct->ct_type->ct_type_ops->contop_qack(ct, evtype, evid));
+}
+
/*
* contract_orphan
*
@@ -840,6 +940,20 @@ contract_exit(proc_t *p)
}
}
+static int
+get_time_left(struct ct_time *t)
+{
+ clock_t ticks_elapsed;
+ int secs_elapsed;
+
+ if (t->ctm_total == -1)
+ return (-1);
+
+ ticks_elapsed = ddi_get_lbolt() - t->ctm_start;
+ secs_elapsed = t->ctm_total - (drv_hztousec(ticks_elapsed)/MICROSEC);
+ return (secs_elapsed > 0 ? secs_elapsed : 0);
+}
+
/*
* contract_status_common
*
@@ -897,8 +1011,8 @@ contract_status_common(contract_t *ct, zone_t *zone, void *status,
CTS_OWNED : ct->ct_state);
}
STRUCT_FSET(lstatus, ctst_nevents, ct->ct_evcnt);
- STRUCT_FSET(lstatus, ctst_ntime, -1);
- STRUCT_FSET(lstatus, ctst_qtime, -1);
+ STRUCT_FSET(lstatus, ctst_ntime, get_time_left(&ct->ct_ntime));
+ STRUCT_FSET(lstatus, ctst_qtime, get_time_left(&ct->ct_qtime));
STRUCT_FSET(lstatus, ctst_nevid,
ct->ct_nevent ? ct->ct_nevent->cte_id : 0);
STRUCT_FSET(lstatus, ctst_critical, ct->ct_ev_crit);
@@ -1469,9 +1583,9 @@ ctmpl_clear(ct_template_t *template)
* Creates a new contract using the specified template.
*/
int
-ctmpl_create(ct_template_t *template)
+ctmpl_create(ct_template_t *template, ctid_t *ctidp)
{
- return (template->ctmpl_ops->ctop_create(template));
+ return (template->ctmpl_ops->ctop_create(template, ctidp));
}
/*
@@ -1520,7 +1634,7 @@ ctmpl_copy(ct_template_t *new, ct_template_t *old)
*/
/*ARGSUSED*/
int
-ctmpl_create_inval(ct_template_t *template)
+ctmpl_create_inval(ct_template_t *template, ctid_t *ctidp)
{
return (EINVAL);
}
@@ -2046,19 +2160,34 @@ cte_publish(ct_equeue_t *q, ct_kevent_t *e, timespec_t *tsp)
* be zallocated by the caller, and the event's flags and type must be
* set. The rest of the event's fields are initialized here.
*/
-void
+uint64_t
cte_publish_all(contract_t *ct, ct_kevent_t *e, nvlist_t *data, nvlist_t *gdata)
{
ct_equeue_t *q;
timespec_t ts;
+ uint64_t evid;
+ ct_kevent_t *negev;
+ int negend;
e->cte_contract = ct;
e->cte_data = data;
e->cte_gdata = gdata;
e->cte_refs = 3;
- e->cte_id = atomic_add_64_nv(&ct->ct_type->ct_type_evid, 1);
+ evid = e->cte_id = atomic_add_64_nv(&ct->ct_type->ct_type_evid, 1);
contract_hold(ct);
+ /*
+ * For a negotiation event we set the ct->ct_nevent field of the
+ * contract for the duration of the negotiation
+ */
+ negend = 0;
+ if (e->cte_flags & CTE_NEG) {
+ cte_hold(e);
+ ct->ct_nevent = e;
+ } else if (e->cte_type == CT_EV_NEGEND) {
+ negend = 1;
+ }
+
gethrestime(&ts);
/*
@@ -2111,7 +2240,17 @@ cte_publish_all(contract_t *ct, ct_kevent_t *e, nvlist_t *data, nvlist_t *gdata)
cte_rele(e);
}
+ if (negend) {
+ mutex_enter(&ct->ct_lock);
+ negev = ct->ct_nevent;
+ ct->ct_nevent = NULL;
+ cte_rele(negev);
+ mutex_exit(&ct->ct_lock);
+ }
+
mutex_exit(&ct->ct_evtlock);
+
+ return (evid);
}
/*
@@ -2347,7 +2486,8 @@ cte_get_event(ct_listener_t *l, int nonblock, void *uaddr, const cred_t *cr,
STRUCT_FSET(ev, ctev_evid, temp->cte_id);
STRUCT_FSET(ev, ctev_cttype,
temp->cte_contract->ct_type->ct_type_index);
- STRUCT_FSET(ev, ctev_flags, temp->cte_flags & (CTE_ACK|CTE_INFO));
+ STRUCT_FSET(ev, ctev_flags, temp->cte_flags &
+ (CTE_ACK|CTE_INFO|CTE_NEG));
STRUCT_FSET(ev, ctev_type, temp->cte_type);
STRUCT_FSET(ev, ctev_nbytes, len);
STRUCT_FSET(ev, ctev_goffset, size);