/* * 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. */ #include #include #include #include #include #include #include #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); } }