1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <stdarg.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <sys/types.h> 38 #include <sys/time.h> 39 #include <limits.h> 40 41 #include "dispadmin.h" 42 43 44 /* 45 * Utility functions for dispadmin command. 46 */ 47 48 49 void 50 fatalerr(const char *format, ...) 51 { 52 va_list ap; 53 54 (void) va_start(ap, format); 55 (void) vfprintf(stderr, format, ap); 56 va_end(ap); 57 exit(1); 58 } 59 60 61 /* 62 * hrtconvert() returns the interval specified by htp as a single 63 * value in resolution htp->hrt_res. Returns -1 on overflow. 64 */ 65 long 66 hrtconvert(hrtimer_t *htp) 67 { 68 long sum; 69 long product; 70 71 product = htp->hrt_secs * htp->hrt_res; 72 73 if (product / htp->hrt_res == htp->hrt_secs) { 74 sum = product + htp->hrt_rem; 75 if (sum - htp->hrt_rem == product) { 76 return (sum); 77 } 78 } 79 return (-1); 80 } 81 82 /* 83 * The following routine was removed from libc (libc/port/gen/hrtnewres.c). 84 * It has also been added to priocntl, so if you fix it here, you should 85 * also probably fix it there. In the long term, this should be recoded to 86 * not be hrt'ish. 87 */ 88 89 /* 90 * Convert interval expressed in htp->hrt_res to new_res. 91 * 92 * Calculate: (interval * new_res) / htp->hrt_res rounding off as 93 * specified by round. 94 * 95 * Note: All args are assumed to be positive. If 96 * the last divide results in something bigger than 97 * a long, then -1 is returned instead. 98 */ 99 100 int 101 _hrtnewres(hrtimer_t *htp, ulong_t new_res, long round) 102 { 103 long interval; 104 longlong_t dint; 105 longlong_t dto_res; 106 longlong_t drem; 107 longlong_t dfrom_res; 108 longlong_t prod; 109 longlong_t quot; 110 long numerator; 111 long result; 112 ulong_t modulus; 113 ulong_t twomodulus; 114 long temp; 115 116 if (htp->hrt_res == 0 || new_res == 0 || 117 new_res > NANOSEC || htp->hrt_rem < 0) 118 return (-1); 119 120 if (htp->hrt_rem >= htp->hrt_res) { 121 htp->hrt_secs += htp->hrt_rem / htp->hrt_res; 122 htp->hrt_rem = htp->hrt_rem % htp->hrt_res; 123 } 124 125 interval = htp->hrt_rem; 126 if (interval == 0) { 127 htp->hrt_res = new_res; 128 return (0); 129 } 130 131 /* 132 * Try to do the calculations in single precision first 133 * (for speed). If they overflow, use double precision. 134 * What we want to compute is: 135 * 136 * (interval * new_res) / hrt->hrt_res 137 */ 138 139 numerator = interval * new_res; 140 141 if (numerator / new_res == interval) { 142 143 /* 144 * The above multiply didn't give overflow since 145 * the division got back the original number. Go 146 * ahead and compute the result. 147 */ 148 149 result = numerator / htp->hrt_res; 150 151 /* 152 * For HRT_RND, compute the value of: 153 * 154 * (interval * new_res) % htp->hrt_res 155 * 156 * If it is greater than half of the htp->hrt_res, 157 * then rounding increases the result by 1. 158 * 159 * For HRT_RNDUP, we increase the result by 1 if: 160 * 161 * result * htp->hrt_res != numerator 162 * 163 * because this tells us we truncated when calculating 164 * result above. 165 * 166 * We also check for overflow when incrementing result 167 * although this is extremely rare. 168 */ 169 170 if (round == HRT_RND) { 171 modulus = numerator - result * htp->hrt_res; 172 if ((twomodulus = 2 * modulus) / 2 == modulus) { 173 174 /* 175 * No overflow (if we overflow in calculation 176 * of twomodulus we fall through and use 177 * double precision). 178 */ 179 if (twomodulus >= htp->hrt_res) { 180 temp = result + 1; 181 if (temp - 1 == result) 182 result++; 183 else 184 return (-1); 185 } 186 htp->hrt_res = new_res; 187 htp->hrt_rem = result; 188 return (0); 189 } 190 } else if (round == HRT_RNDUP) { 191 if (result * htp->hrt_res != numerator) { 192 temp = result + 1; 193 if (temp - 1 == result) 194 result++; 195 else 196 return (-1); 197 } 198 htp->hrt_res = new_res; 199 htp->hrt_rem = result; 200 return (0); 201 } else { /* round == HRT_TRUNC */ 202 htp->hrt_res = new_res; 203 htp->hrt_rem = result; 204 return (0); 205 } 206 } 207 208 /* 209 * We would get overflow doing the calculation is 210 * single precision so do it the slow but careful way. 211 * 212 * Compute the interval times the resolution we are 213 * going to. 214 */ 215 216 dint = interval; 217 dto_res = new_res; 218 prod = dint * dto_res; 219 220 /* 221 * For HRT_RND the result will be equal to: 222 * 223 * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res 224 * 225 * and for HRT_RNDUP we use: 226 * 227 * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res 228 * 229 * This is a different but equivalent way of rounding. 230 */ 231 232 if (round == HRT_RND) { 233 drem = htp->hrt_res / 2; 234 prod = prod + drem; 235 } else if (round == HRT_RNDUP) { 236 drem = htp->hrt_res - 1; 237 prod = prod + drem; 238 } 239 240 dfrom_res = htp->hrt_res; 241 quot = prod / dfrom_res; 242 243 /* 244 * If the quotient won't fit in a long, then we have 245 * overflow. Otherwise, return the result. 246 */ 247 248 if (quot > UINT_MAX) { 249 return (-1); 250 } else { 251 htp->hrt_res = new_res; 252 htp->hrt_rem = (int)quot; 253 return (0); 254 } 255 } 256