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 #include <stdio.h> 32 #include <stdarg.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <sys/types.h> 36 #include <sys/time.h> 37 #include <limits.h> 38 39 #include "dispadmin.h" 40 41 42 /* 43 * Utility functions for dispadmin command. 44 */ 45 46 47 void 48 fatalerr(const char *format, ...) 49 { 50 va_list ap; 51 52 (void) va_start(ap, format); 53 (void) vfprintf(stderr, format, ap); 54 va_end(ap); 55 exit(1); 56 } 57 58 59 /* 60 * hrtconvert() returns the interval specified by htp as a single 61 * value in resolution htp->hrt_res. Returns -1 on overflow. 62 */ 63 long 64 hrtconvert(hrtimer_t *htp) 65 { 66 long sum; 67 long product; 68 69 product = htp->hrt_secs * htp->hrt_res; 70 71 if (product / htp->hrt_res == htp->hrt_secs) { 72 sum = product + htp->hrt_rem; 73 if (sum - htp->hrt_rem == product) { 74 return (sum); 75 } 76 } 77 return (-1); 78 } 79 80 /* 81 * The following routine was removed from libc (libc/port/gen/hrtnewres.c). 82 * It has also been added to priocntl, so if you fix it here, you should 83 * also probably fix it there. In the long term, this should be recoded to 84 * not be hrt'ish. 85 */ 86 87 /* 88 * Convert interval expressed in htp->hrt_res to new_res. 89 * 90 * Calculate: (interval * new_res) / htp->hrt_res rounding off as 91 * specified by round. 92 * 93 * Note: All args are assumed to be positive. If 94 * the last divide results in something bigger than 95 * a long, then -1 is returned instead. 96 */ 97 98 int 99 _hrtnewres(hrtimer_t *htp, ulong_t new_res, long round) 100 { 101 long interval; 102 longlong_t dint; 103 longlong_t dto_res; 104 longlong_t drem; 105 longlong_t dfrom_res; 106 longlong_t prod; 107 longlong_t quot; 108 long numerator; 109 long result; 110 ulong_t modulus; 111 ulong_t twomodulus; 112 long temp; 113 114 if (htp->hrt_res == 0 || new_res == 0 || 115 new_res > NANOSEC || htp->hrt_rem < 0) 116 return (-1); 117 118 if (htp->hrt_rem >= htp->hrt_res) { 119 htp->hrt_secs += htp->hrt_rem / htp->hrt_res; 120 htp->hrt_rem = htp->hrt_rem % htp->hrt_res; 121 } 122 123 interval = htp->hrt_rem; 124 if (interval == 0) { 125 htp->hrt_res = new_res; 126 return (0); 127 } 128 129 /* 130 * Try to do the calculations in single precision first 131 * (for speed). If they overflow, use double precision. 132 * What we want to compute is: 133 * 134 * (interval * new_res) / hrt->hrt_res 135 */ 136 137 numerator = interval * new_res; 138 139 if (numerator / new_res == interval) { 140 141 /* 142 * The above multiply didn't give overflow since 143 * the division got back the original number. Go 144 * ahead and compute the result. 145 */ 146 147 result = numerator / htp->hrt_res; 148 149 /* 150 * For HRT_RND, compute the value of: 151 * 152 * (interval * new_res) % htp->hrt_res 153 * 154 * If it is greater than half of the htp->hrt_res, 155 * then rounding increases the result by 1. 156 * 157 * For HRT_RNDUP, we increase the result by 1 if: 158 * 159 * result * htp->hrt_res != numerator 160 * 161 * because this tells us we truncated when calculating 162 * result above. 163 * 164 * We also check for overflow when incrementing result 165 * although this is extremely rare. 166 */ 167 168 if (round == HRT_RND) { 169 modulus = numerator - result * htp->hrt_res; 170 if ((twomodulus = 2 * modulus) / 2 == modulus) { 171 172 /* 173 * No overflow (if we overflow in calculation 174 * of twomodulus we fall through and use 175 * double precision). 176 */ 177 if (twomodulus >= htp->hrt_res) { 178 temp = result + 1; 179 if (temp - 1 == result) 180 result++; 181 else 182 return (-1); 183 } 184 htp->hrt_res = new_res; 185 htp->hrt_rem = result; 186 return (0); 187 } 188 } else if (round == HRT_RNDUP) { 189 if (result * htp->hrt_res != numerator) { 190 temp = result + 1; 191 if (temp - 1 == result) 192 result++; 193 else 194 return (-1); 195 } 196 htp->hrt_res = new_res; 197 htp->hrt_rem = result; 198 return (0); 199 } else { /* round == HRT_TRUNC */ 200 htp->hrt_res = new_res; 201 htp->hrt_rem = result; 202 return (0); 203 } 204 } 205 206 /* 207 * We would get overflow doing the calculation is 208 * single precision so do it the slow but careful way. 209 * 210 * Compute the interval times the resolution we are 211 * going to. 212 */ 213 214 dint = interval; 215 dto_res = new_res; 216 prod = dint * dto_res; 217 218 /* 219 * For HRT_RND the result will be equal to: 220 * 221 * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res 222 * 223 * and for HRT_RNDUP we use: 224 * 225 * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res 226 * 227 * This is a different but equivalent way of rounding. 228 */ 229 230 if (round == HRT_RND) { 231 drem = htp->hrt_res / 2; 232 prod = prod + drem; 233 } else if (round == HRT_RNDUP) { 234 drem = htp->hrt_res - 1; 235 prod = prod + drem; 236 } 237 238 dfrom_res = htp->hrt_res; 239 quot = prod / dfrom_res; 240 241 /* 242 * If the quotient won't fit in a long, then we have 243 * overflow. Otherwise, return the result. 244 */ 245 246 if (quot > UINT_MAX) { 247 return (-1); 248 } else { 249 htp->hrt_res = new_res; 250 htp->hrt_rem = (int)quot; 251 return (0); 252 } 253 } 254