summaryrefslogtreecommitdiff
path: root/usr/src/cmd/dispadmin/subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/dispadmin/subr.c')
-rw-r--r--usr/src/cmd/dispadmin/subr.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/usr/src/cmd/dispadmin/subr.c b/usr/src/cmd/dispadmin/subr.c
new file mode 100644
index 0000000000..b2c5c10b4a
--- /dev/null
+++ b/usr/src/cmd/dispadmin/subr.c
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <limits.h>
+
+#include "dispadmin.h"
+
+
+/*
+ * Utility functions for dispadmin command.
+ */
+
+
+void
+fatalerr(const char *format, ...)
+{
+ va_list ap;
+
+ (void) va_start(ap, format);
+ (void) vfprintf(stderr, format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+
+/*
+ * hrtconvert() returns the interval specified by htp as a single
+ * value in resolution htp->hrt_res. Returns -1 on overflow.
+ */
+long
+hrtconvert(hrtimer_t *htp)
+{
+ long sum;
+ long product;
+
+ product = htp->hrt_secs * htp->hrt_res;
+
+ if (product / htp->hrt_res == htp->hrt_secs) {
+ sum = product + htp->hrt_rem;
+ if (sum - htp->hrt_rem == product) {
+ return (sum);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * The following routine was removed from libc (libc/port/gen/hrtnewres.c).
+ * It has also been added to priocntl, so if you fix it here, you should
+ * also probably fix it there. In the long term, this should be recoded to
+ * not be hrt'ish.
+ */
+
+/*
+ * Convert interval expressed in htp->hrt_res to new_res.
+ *
+ * Calculate: (interval * new_res) / htp->hrt_res rounding off as
+ * specified by round.
+ *
+ * Note: All args are assumed to be positive. If
+ * the last divide results in something bigger than
+ * a long, then -1 is returned instead.
+ */
+
+int
+_hrtnewres(hrtimer_t *htp, ulong_t new_res, long round)
+{
+ long interval;
+ longlong_t dint;
+ longlong_t dto_res;
+ longlong_t drem;
+ longlong_t dfrom_res;
+ longlong_t prod;
+ longlong_t quot;
+ long numerator;
+ long result;
+ ulong_t modulus;
+ ulong_t twomodulus;
+ long temp;
+
+ if (htp->hrt_res == 0 || new_res == 0 ||
+ new_res > NANOSEC || htp->hrt_rem < 0)
+ return (-1);
+
+ if (htp->hrt_rem >= htp->hrt_res) {
+ htp->hrt_secs += htp->hrt_rem / htp->hrt_res;
+ htp->hrt_rem = htp->hrt_rem % htp->hrt_res;
+ }
+
+ interval = htp->hrt_rem;
+ if (interval == 0) {
+ htp->hrt_res = new_res;
+ return (0);
+ }
+
+ /*
+ * Try to do the calculations in single precision first
+ * (for speed). If they overflow, use double precision.
+ * What we want to compute is:
+ *
+ * (interval * new_res) / hrt->hrt_res
+ */
+
+ numerator = interval * new_res;
+
+ if (numerator / new_res == interval) {
+
+ /*
+ * The above multiply didn't give overflow since
+ * the division got back the original number. Go
+ * ahead and compute the result.
+ */
+
+ result = numerator / htp->hrt_res;
+
+ /*
+ * For HRT_RND, compute the value of:
+ *
+ * (interval * new_res) % htp->hrt_res
+ *
+ * If it is greater than half of the htp->hrt_res,
+ * then rounding increases the result by 1.
+ *
+ * For HRT_RNDUP, we increase the result by 1 if:
+ *
+ * result * htp->hrt_res != numerator
+ *
+ * because this tells us we truncated when calculating
+ * result above.
+ *
+ * We also check for overflow when incrementing result
+ * although this is extremely rare.
+ */
+
+ if (round == HRT_RND) {
+ modulus = numerator - result * htp->hrt_res;
+ if ((twomodulus = 2 * modulus) / 2 == modulus) {
+
+ /*
+ * No overflow (if we overflow in calculation
+ * of twomodulus we fall through and use
+ * double precision).
+ */
+ if (twomodulus >= htp->hrt_res) {
+ temp = result + 1;
+ if (temp - 1 == result)
+ result++;
+ else
+ return (-1);
+ }
+ htp->hrt_res = new_res;
+ htp->hrt_rem = result;
+ return (0);
+ }
+ } else if (round == HRT_RNDUP) {
+ if (result * htp->hrt_res != numerator) {
+ temp = result + 1;
+ if (temp - 1 == result)
+ result++;
+ else
+ return (-1);
+ }
+ htp->hrt_res = new_res;
+ htp->hrt_rem = result;
+ return (0);
+ } else { /* round == HRT_TRUNC */
+ htp->hrt_res = new_res;
+ htp->hrt_rem = result;
+ return (0);
+ }
+ }
+
+ /*
+ * We would get overflow doing the calculation is
+ * single precision so do it the slow but careful way.
+ *
+ * Compute the interval times the resolution we are
+ * going to.
+ */
+
+ dint = interval;
+ dto_res = new_res;
+ prod = dint * dto_res;
+
+ /*
+ * For HRT_RND the result will be equal to:
+ *
+ * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res
+ *
+ * and for HRT_RNDUP we use:
+ *
+ * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res
+ *
+ * This is a different but equivalent way of rounding.
+ */
+
+ if (round == HRT_RND) {
+ drem = htp->hrt_res / 2;
+ prod = prod + drem;
+ } else if (round == HRT_RNDUP) {
+ drem = htp->hrt_res - 1;
+ prod = prod + drem;
+ }
+
+ dfrom_res = htp->hrt_res;
+ quot = prod / dfrom_res;
+
+ /*
+ * If the quotient won't fit in a long, then we have
+ * overflow. Otherwise, return the result.
+ */
+
+ if (quot > UINT_MAX) {
+ return (-1);
+ } else {
+ htp->hrt_res = new_res;
+ htp->hrt_rem = (int)quot;
+ return (0);
+ }
+}