Changes in uspace/lib/c/generic/time.c [f9b2cb4c:3e6a98c5] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/time.c
rf9b2cb4c r3e6a98c5 54 54 #include <malloc.h> 55 55 56 #define ASCTIME_BUF_LEN 26 57 58 #define HOURS_PER_DAY 24 59 #define MINS_PER_HOUR 60 60 #define SECS_PER_MIN 60 61 #define USECS_PER_SEC 1000000 62 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 63 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 64 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 56 #define ASCTIME_BUF_LEN 26 65 57 66 58 /** Pointer to kernel shared variables with time */ … … 71 63 } *ktime = NULL; 72 64 73 static async_sess_t *clock_conn = NULL; 74 75 /** Check whether the year is a leap year. 65 /* Helper functions ***********************************************************/ 66 67 #define HOURS_PER_DAY (24) 68 #define MINS_PER_HOUR (60) 69 #define SECS_PER_MIN (60) 70 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 71 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 72 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 73 74 /** 75 * Checks whether the year is a leap year. 76 76 * 77 77 * @param year Year since 1900 (e.g. for 1970, the value is 70). 78 *79 78 * @return true if year is a leap year, false otherwise 80 * 81 */ 82 static bool is_leap_year(time_t year) 79 */ 80 static bool _is_leap_year(time_t year) 83 81 { 84 82 year += 1900; 85 83 86 84 if (year % 400 == 0) 87 85 return true; 88 89 86 if (year % 100 == 0) 90 87 return false; 91 92 88 if (year % 4 == 0) 93 89 return true; 94 95 90 return false; 96 91 } 97 92 98 /** How many days there are in the given month 99 * 100 * Return how many days there are in the given month of the given year. 93 /** 94 * Returns how many days there are in the given month of the given year. 101 95 * Note that year is only taken into account if month is February. 102 96 * 103 97 * @param year Year since 1900 (can be negative). 104 * @param mon Month of the year. 0 for January, 11 for December. 105 * 98 * @param mon Month of the year. 0 for January, 11 for December. 106 99 * @return Number of days in the specified month. 107 * 108 */ 109 static int days_in_month(time_t year, time_t mon) 110 { 111 assert(mon >= 0); 112 assert(mon <= 11); 113 114 static int month_days[] = { 115 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 116 }; 117 100 */ 101 static int _days_in_month(time_t year, time_t mon) 102 { 103 assert(mon >= 0 && mon <= 11); 104 105 static int month_days[] = 106 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 107 118 108 if (mon == 1) { 119 /* February */120 109 year += 1900; 121 return is_leap_year(year) ? 29 : 28;122 }123 124 return month_days[mon];125 }126 127 /** Which day of that year it is. 128 129 * For specified year, month and day of month, return which day of that year110 /* february */ 111 return _is_leap_year(year) ? 29 : 28; 112 } else { 113 return month_days[mon]; 114 } 115 } 116 117 /** 118 * For specified year, month and day of month, returns which day of that year 130 119 * it is. 131 120 * 132 121 * For example, given date 2011-01-03, the corresponding expression is: 133 * day_of_year(111, 0, 3) == 2122 * _day_of_year(111, 0, 3) == 2 134 123 * 135 124 * @param year Year (year 1900 = 0, can be negative). 136 * @param mon 125 * @param mon Month (January = 0). 137 126 * @param mday Day of month (First day is 1). 138 *139 127 * @return Day of year (First day is 0). 140 * 141 */ 142 static int day_of_year(time_t year, time_t mon, time_t mday) 143 { 144 static int mdays[] = { 145 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 146 }; 147 148 static int leap_mdays[] = { 149 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 150 }; 151 152 return (is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 153 } 154 155 /** Integer division that rounds to negative infinity. 156 * 157 * Used by some functions in this module. 128 */ 129 static int _day_of_year(time_t year, time_t mon, time_t mday) 130 { 131 static int mdays[] = 132 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 133 static int leap_mdays[] = 134 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; 135 136 return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 137 } 138 139 /** 140 * Integer division that rounds to negative infinity. 141 * Used by some functions in this file. 158 142 * 159 143 * @param op1 Dividend. 160 144 * @param op2 Divisor. 161 *162 145 * @return Rounded quotient. 163 * 164 */ 165 static time_t floor_div(time_t op1, time_t op2) 166 { 167 if ((op1 >= 0) || (op1 % op2 == 0)) 146 */ 147 static time_t _floor_div(time_t op1, time_t op2) 148 { 149 if (op1 >= 0 || op1 % op2 == 0) { 168 150 return op1 / op2; 169 170 return op1 / op2 - 1; 171 } 172 173 /** Modulo that rounds to negative infinity. 174 * 175 * Used by some functions in this module. 151 } else { 152 return op1 / op2 - 1; 153 } 154 } 155 156 /** 157 * Modulo that rounds to negative infinity. 158 * Used by some functions in this file. 176 159 * 177 160 * @param op1 Dividend. 178 161 * @param op2 Divisor. 179 *180 162 * @return Remainder. 181 * 182 */ 183 static time_t floor_mod(time_t op1, time_t op2) 184 { 185 time_t div = floor_div(op1, op2); 186 187 /* 188 * (a / b) * b + a % b == a 189 * Thus: a % b == a - (a / b) * b 190 */ 191 192 time_t result = op1 - div * op2; 193 194 /* Some paranoid checking to ensure there is mistake here. */ 163 */ 164 static time_t _floor_mod(time_t op1, time_t op2) 165 { 166 int div = _floor_div(op1, op2); 167 168 /* (a / b) * b + a % b == a */ 169 /* thus, a % b == a - (a / b) * b */ 170 171 int result = op1 - div * op2; 172 173 /* Some paranoid checking to ensure I didn't make a mistake here. */ 195 174 assert(result >= 0); 196 175 assert(result < op2); … … 200 179 } 201 180 202 /** Number of days since the Epoch.203 * 181 /** 182 * Number of days since the Epoch. 204 183 * Epoch is 1970-01-01, which is also equal to day 0. 205 184 * 206 185 * @param year Year (year 1900 = 0, may be negative). 207 * @param mon 186 * @param mon Month (January = 0). 208 187 * @param mday Day of month (first day = 1). 209 *210 188 * @return Number of days since the Epoch. 211 * 212 */ 213 static time_t days_since_epoch(time_t year, time_t mon, time_t mday) 214 { 215 return (year - 70) * 365 + floor_div(year - 69, 4) - 216 floor_div(year - 1, 100) + floor_div(year + 299, 400) + 217 day_of_year(year, mon, mday); 218 } 219 220 /** Seconds since the Epoch. 221 * 222 * See also days_since_epoch(). 223 * 189 */ 190 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) 191 { 192 return (year - 70) * 365 + _floor_div(year - 69, 4) - 193 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) + 194 _day_of_year(year, mon, mday); 195 } 196 197 /** 198 * Seconds since the Epoch. see also _days_since_epoch(). 199 * 224 200 * @param tm Normalized broken-down time. 225 *226 201 * @return Number of seconds since the epoch, not counting leap seconds. 227 * 228 */ 229 static time_t secs_since_epoch(const struct tm *tm) 230 { 231 return days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 202 */ 203 static time_t _secs_since_epoch(const struct tm *tm) 204 { 205 return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 232 206 SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR + 233 207 tm->tm_min * SECS_PER_MIN + tm->tm_sec; 234 208 } 235 209 236 /** Which day of week the specified date is. 237 * 210 /** 211 * Which day of week the specified date is. 212 * 238 213 * @param year Year (year 1900 = 0). 239 * @param mon 214 * @param mon Month (January = 0). 240 215 * @param mday Day of month (first = 1). 241 *242 216 * @return Day of week (Sunday = 0). 243 * 244 */ 245 static time_t day_of_week(time_t year, time_t mon, time_t mday) 217 */ 218 static int _day_of_week(time_t year, time_t mon, time_t mday) 246 219 { 247 220 /* 1970-01-01 is Thursday */ 248 return floor_mod(days_since_epoch(year, mon, mday) + 4, 7);249 } 250 251 /** Normalize the broken-down time.252 * 253 * Optionally add specified amount ofseconds.254 * 221 return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7); 222 } 223 224 /** 225 * Normalizes the broken-down time and optionally adds specified amount of 226 * seconds. 227 * 255 228 * @param tm Broken-down time to normalize. 256 * @param tv Timeval to add. 257 * 229 * @param sec_add Seconds to add. 258 230 * @return 0 on success, -1 on overflow 259 * 260 */ 261 static int normalize_tm_tv(struct tm *tm, const struct timeval *tv) 231 */ 232 static int _normalize_time(struct tm *tm, time_t sec_add) 262 233 { 263 234 // TODO: DST correction 264 235 265 236 /* Set initial values. */ 266 time_t usec = tm->tm_usec + tv->tv_usec; 267 time_t sec = tm->tm_sec + tv->tv_sec; 237 time_t sec = tm->tm_sec + sec_add; 268 238 time_t min = tm->tm_min; 269 239 time_t hour = tm->tm_hour; … … 271 241 time_t mon = tm->tm_mon; 272 242 time_t year = tm->tm_year; 273 243 274 244 /* Adjust time. */ 275 sec += floor_div(usec, USECS_PER_SEC); 276 usec = floor_mod(usec, USECS_PER_SEC); 277 min += floor_div(sec, SECS_PER_MIN); 278 sec = floor_mod(sec, SECS_PER_MIN); 279 hour += floor_div(min, MINS_PER_HOUR); 280 min = floor_mod(min, MINS_PER_HOUR); 281 day += floor_div(hour, HOURS_PER_DAY); 282 hour = floor_mod(hour, HOURS_PER_DAY); 283 245 min += _floor_div(sec, SECS_PER_MIN); 246 sec = _floor_mod(sec, SECS_PER_MIN); 247 hour += _floor_div(min, MINS_PER_HOUR); 248 min = _floor_mod(min, MINS_PER_HOUR); 249 day += _floor_div(hour, HOURS_PER_DAY); 250 hour = _floor_mod(hour, HOURS_PER_DAY); 251 284 252 /* Adjust month. */ 285 year += floor_div(mon, 12);286 mon = floor_mod(mon, 12);287 253 year += _floor_div(mon, 12); 254 mon = _floor_mod(mon, 12); 255 288 256 /* Now the difficult part - days of month. */ 289 257 290 258 /* First, deal with whole cycles of 400 years = 146097 days. */ 291 year += floor_div(day, 146097) * 400;292 day = floor_mod(day, 146097);259 year += _floor_div(day, 146097) * 400; 260 day = _floor_mod(day, 146097); 293 261 294 262 /* Then, go in one year steps. */ … … 296 264 /* January and February. */ 297 265 while (day > 365) { 298 day -= is_leap_year(year) ? 366 : 365;266 day -= _is_leap_year(year) ? 366 : 365; 299 267 year++; 300 268 } … … 302 270 /* Rest of the year. */ 303 271 while (day > 365) { 304 day -= is_leap_year(year + 1) ? 366 : 365;272 day -= _is_leap_year(year + 1) ? 366 : 365; 305 273 year++; 306 274 } … … 308 276 309 277 /* Finally, finish it off month per month. */ 310 while (day >= days_in_month(year, mon)) {311 day -= days_in_month(year, mon);278 while (day >= _days_in_month(year, mon)) { 279 day -= _days_in_month(year, mon); 312 280 mon++; 313 314 281 if (mon >= 12) { 315 282 mon -= 12; … … 319 286 320 287 /* Calculate the remaining two fields. */ 321 tm->tm_yday = day_of_year(year, mon, day + 1);322 tm->tm_wday = day_of_week(year, mon, day + 1);288 tm->tm_yday = _day_of_year(year, mon, day + 1); 289 tm->tm_wday = _day_of_week(year, mon, day + 1); 323 290 324 291 /* And put the values back to the struct. */ 325 tm->tm_usec = (int) usec;326 292 tm->tm_sec = (int) sec; 327 293 tm->tm_min = (int) min; … … 330 296 tm->tm_mon = (int) mon; 331 297 332 /* Casts to work around POSIXbrain-damage. */333 if (year > ((int) INT_MAX) || year < ((int)INT_MIN)) {334 tm->tm_year = (year < 0) ? ((int) INT_MIN) : ((int)INT_MAX);298 /* Casts to work around libc brain-damage. */ 299 if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) { 300 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX); 335 301 return -1; 336 302 } … … 340 306 } 341 307 342 static int normalize_tm_time(struct tm *tm, time_t time) 343 { 344 struct timeval tv = { 345 .tv_sec = time, 346 .tv_usec = 0 347 }; 348 349 return normalize_tm_tv(tm, &tv); 350 } 351 352 353 /** Which day the week-based year starts on. 354 * 355 * Relative to the first calendar day. E.g. if the year starts 356 * on December 31st, the return value is -1. 308 /** 309 * Which day the week-based year starts on, relative to the first calendar day. 310 * E.g. if the year starts on December 31st, the return value is -1. 357 311 * 358 312 * @param Year since 1900. 359 *360 313 * @return Offset of week-based year relative to calendar year. 361 * 362 */ 363 static int wbyear_offset(int year) 364 { 365 int start_wday = day_of_week(year, 0, 1); 366 367 return floor_mod(4 - start_wday, 7) - 3; 368 } 369 370 /** Week-based year of the specified time. 314 */ 315 static int _wbyear_offset(int year) 316 { 317 int start_wday = _day_of_week(year, 0, 1); 318 return _floor_mod(4 - start_wday, 7) - 3; 319 } 320 321 /** 322 * Returns week-based year of the specified time. 371 323 * 372 324 * @param tm Normalized broken-down time. 373 *374 325 * @return Week-based year. 375 * 376 */ 377 static int wbyear(const struct tm *tm) 378 { 379 int day = tm->tm_yday - wbyear_offset(tm->tm_year); 380 326 */ 327 static int _wbyear(const struct tm *tm) 328 { 329 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 381 330 if (day < 0) { 382 331 /* Last week of previous year. */ 383 332 return tm->tm_year - 1; 384 333 } 385 386 if (day > 364 + is_leap_year(tm->tm_year)) { 334 if (day > 364 + _is_leap_year(tm->tm_year)) { 387 335 /* First week of next year. */ 388 336 return tm->tm_year + 1; 389 337 } 390 391 338 /* All the other days are in the calendar year. */ 392 339 return tm->tm_year; 393 340 } 394 341 395 /** Week number of the year (assuming weeks start on Sunday).396 * 342 /** 343 * Week number of the year, assuming weeks start on sunday. 397 344 * The first Sunday of January is the first day of week 1; 398 345 * days in the new year before this are in week 0. 399 346 * 400 347 * @param tm Normalized broken-down time. 401 *402 348 * @return The week number (0 - 53). 403 * 404 */ 405 static int sun_week_number(const struct tm *tm) 406 { 407 int first_day = (7 - day_of_week(tm->tm_year, 0, 1)) % 7; 408 349 */ 350 static int _sun_week_number(const struct tm *tm) 351 { 352 int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7; 409 353 return (tm->tm_yday - first_day + 7) / 7; 410 354 } 411 355 412 /** Week number of the year (assuming weeks start on Monday). 413 * 414 * If the week containing January 1st has four or more days 415 * in the new year, then it is considered week 1. Otherwise, 416 * it is the last week of the previous year, and the next week 417 * is week 1. Both January 4th and the first Thursday 356 /** 357 * Week number of the year, assuming weeks start on monday. 358 * If the week containing January 1st has four or more days in the new year, 359 * then it is considered week 1. Otherwise, it is the last week of the previous 360 * year, and the next week is week 1. Both January 4th and the first Thursday 418 361 * of January are always in week 1. 419 362 * 420 363 * @param tm Normalized broken-down time. 421 *422 364 * @return The week number (1 - 53). 423 * 424 */ 425 static int iso_week_number(const struct tm *tm) 426 { 427 int day = tm->tm_yday - wbyear_offset(tm->tm_year); 428 365 */ 366 static int _iso_week_number(const struct tm *tm) 367 { 368 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 429 369 if (day < 0) { 430 370 /* Last week of previous year. */ 431 371 return 53; 432 372 } 433 434 if (day > 364 + is_leap_year(tm->tm_year)) { 373 if (day > 364 + _is_leap_year(tm->tm_year)) { 435 374 /* First week of next year. */ 436 375 return 1; 437 376 } 438 439 377 /* All the other days give correct answer. */ 440 378 return (day / 7 + 1); 441 379 } 442 380 443 /** Week number of the year (assuming weeks start on Monday).444 * 381 /** 382 * Week number of the year, assuming weeks start on monday. 445 383 * The first Monday of January is the first day of week 1; 446 * days in the new year before this are in week 0. 384 * days in the new year before this are in week 0. 447 385 * 448 386 * @param tm Normalized broken-down time. 449 *450 387 * @return The week number (0 - 53). 451 * 452 */ 453 static int mon_week_number(const struct tm *tm) 454 { 455 int first_day = (1 - day_of_week(tm->tm_year, 0, 1)) % 7; 456 388 */ 389 static int _mon_week_number(const struct tm *tm) 390 { 391 int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7; 457 392 return (tm->tm_yday - first_day + 7) / 7; 458 393 } 459 394 460 static void tv_normalize(struct timeval *tv) 461 { 462 while (tv->tv_usec > USECS_PER_SEC) { 463 tv->tv_sec++; 464 tv->tv_usec -= USECS_PER_SEC; 465 } 466 while (tv->tv_usec < 0) { 467 tv->tv_sec--; 468 tv->tv_usec += USECS_PER_SEC; 469 } 470 } 395 /******************************************************************************/ 396 471 397 472 398 /** Add microseconds to given timeval. … … 476 402 * 477 403 */ 478 void tv_add_diff(struct timeval *tv, suseconds_t usecs) 479 { 480 tv->tv_sec += usecs / USECS_PER_SEC; 481 tv->tv_usec += usecs % USECS_PER_SEC; 482 tv_normalize(tv); 483 } 484 485 /** Add two timevals. 404 void tv_add(struct timeval *tv, suseconds_t usecs) 405 { 406 tv->tv_sec += usecs / 1000000; 407 tv->tv_usec += usecs % 1000000; 408 409 if (tv->tv_usec > 1000000) { 410 tv->tv_sec++; 411 tv->tv_usec -= 1000000; 412 } 413 } 414 415 /** Subtract two timevals. 486 416 * 487 417 * @param tv1 First timeval. 488 418 * @param tv2 Second timeval. 489 */ 490 void tv_add(struct timeval *tv1, struct timeval *tv2) 491 { 492 tv1->tv_sec += tv2->tv_sec; 493 tv1->tv_usec += tv2->tv_usec; 494 tv_normalize(tv1); 495 } 496 497 /** Subtract two timevals. 419 * 420 * @return Difference between tv1 and tv2 (tv1 - tv2) in 421 * microseconds. 422 * 423 */ 424 suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2) 425 { 426 return (tv1->tv_usec - tv2->tv_usec) + 427 ((tv1->tv_sec - tv2->tv_sec) * 1000000); 428 } 429 430 /** Decide if one timeval is greater than the other. 431 * 432 * @param t1 First timeval. 433 * @param t2 Second timeval. 434 * 435 * @return True if tv1 is greater than tv2. 436 * @return False otherwise. 437 * 438 */ 439 int tv_gt(struct timeval *tv1, struct timeval *tv2) 440 { 441 if (tv1->tv_sec > tv2->tv_sec) 442 return true; 443 444 if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec)) 445 return true; 446 447 return false; 448 } 449 450 /** Decide if one timeval is greater than or equal to the other. 498 451 * 499 452 * @param tv1 First timeval. 500 453 * @param tv2 Second timeval. 501 454 * 502 * @return Difference between tv1 and tv2 (tv1 - tv2) in 503 * microseconds. 504 * 505 */ 506 suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2) 507 { 508 return (tv1->tv_usec - tv2->tv_usec) + 509 ((tv1->tv_sec - tv2->tv_sec) * USECS_PER_SEC); 510 } 511 512 /** Subtract two timevals. 513 * 514 * @param tv1 First timeval. 515 * @param tv2 Second timeval. 516 * 517 */ 518 void tv_sub(struct timeval *tv1, struct timeval *tv2) 519 { 520 tv1->tv_sec -= tv2->tv_sec; 521 tv1->tv_usec -= tv2->tv_usec; 522 tv_normalize(tv1); 523 } 524 525 /** Decide if one timeval is greater than the other. 526 * 527 * @param t1 First timeval. 528 * @param t2 Second timeval. 529 * 530 * @return True if tv1 is greater than tv2. 455 * @return True if tv1 is greater than or equal to tv2. 531 456 * @return False otherwise. 532 457 * 533 458 */ 534 int tv_gt (struct timeval *tv1, struct timeval *tv2)459 int tv_gteq(struct timeval *tv1, struct timeval *tv2) 535 460 { 536 461 if (tv1->tv_sec > tv2->tv_sec) 537 462 return true; 538 463 539 if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec > tv2->tv_usec))540 return true;541 542 return false;543 }544 545 /** Decide if one timeval is greater than or equal to the other.546 *547 * @param tv1 First timeval.548 * @param tv2 Second timeval.549 *550 * @return True if tv1 is greater than or equal to tv2.551 * @return False otherwise.552 *553 */554 int tv_gteq(struct timeval *tv1, struct timeval *tv2)555 {556 if (tv1->tv_sec > tv2->tv_sec)557 return true;558 559 464 if ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec >= tv2->tv_usec)) 560 465 return true; … … 563 468 } 564 469 565 /** Get time of day .470 /** Get time of day 566 471 * 567 472 * The time variables are memory mapped (read-only) from kernel which … … 577 482 * 578 483 */ 579 void gettimeofday(struct timeval *tv, struct timezone *tz) 580 { 484 int gettimeofday(struct timeval *tv, struct timezone *tz) 485 { 486 int rc; 487 struct tm t; 488 category_id_t cat_id; 489 size_t svc_cnt; 490 service_id_t *svc_ids = NULL; 491 service_id_t svc_id; 492 char *svc_name = NULL; 493 494 static async_sess_t *clock_conn = NULL; 495 581 496 if (tz) { 582 497 tz->tz_minuteswest = 0; 583 498 tz->tz_dsttime = DST_NONE; 584 499 } 585 500 586 501 if (clock_conn == NULL) { 587 category_id_t cat_id; 588 int rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING); 502 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING); 589 503 if (rc != EOK) 590 goto fallback; 591 592 service_id_t *svc_ids; 593 size_t svc_cnt; 504 goto ret_uptime; 505 594 506 rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt); 595 507 if (rc != EOK) 596 goto fallback;597 508 goto ret_uptime; 509 598 510 if (svc_cnt == 0) 599 goto fallback; 600 601 char *svc_name; 511 goto ret_uptime; 512 602 513 rc = loc_service_get_name(svc_ids[0], &svc_name); 603 free(svc_ids);604 514 if (rc != EOK) 605 goto fallback; 606 607 service_id_t svc_id; 515 goto ret_uptime; 516 608 517 rc = loc_service_get_id(svc_name, &svc_id, 0); 609 free(svc_name);610 518 if (rc != EOK) 611 goto fallback;612 613 clock_conn = loc_service_connect( svc_id, INTERFACE_DDF,614 IPC_FLAG_BLOCKING);519 goto ret_uptime; 520 521 clock_conn = loc_service_connect(EXCHANGE_SERIALIZE, 522 svc_id, IPC_FLAG_BLOCKING); 615 523 if (!clock_conn) 616 goto fallback; 617 } 618 619 struct tm time; 620 int rc = clock_dev_time_get(clock_conn, &time); 524 goto ret_uptime; 525 } 526 527 rc = clock_dev_time_get(clock_conn, &t); 621 528 if (rc != EOK) 622 goto fallback; 623 624 tv->tv_usec = time.tm_usec; 625 tv->tv_sec = mktime(&time); 626 627 return; 628 629 fallback: 630 getuptime(tv); 631 } 632 633 void getuptime(struct timeval *tv) 529 goto ret_uptime; 530 531 tv->tv_usec = 0; 532 tv->tv_sec = mktime(&t); 533 534 free(svc_name); 535 free(svc_ids); 536 537 return EOK; 538 539 ret_uptime: 540 541 free(svc_name); 542 free(svc_ids); 543 544 return getuptime(tv); 545 } 546 547 int getuptime(struct timeval *tv) 634 548 { 635 549 if (ktime == NULL) { … … 638 552 if (rc != EOK) { 639 553 errno = rc; 640 goto fallback;554 return -1; 641 555 } 642 556 643 void *addr = AS_AREA_ANY;644 rc = physmem_map( faddr, 1, AS_AREA_READ | AS_AREA_CACHEABLE,645 &addr);557 void *addr; 558 rc = physmem_map((void *) faddr, 1, 559 AS_AREA_READ | AS_AREA_CACHEABLE, &addr); 646 560 if (rc != EOK) { 647 561 as_area_destroy(addr); 648 562 errno = rc; 649 goto fallback;563 return -1; 650 564 } 651 565 … … 666 580 } else 667 581 tv->tv_sec = s1; 668 669 return; 670 671 fallback: 672 tv->tv_sec = 0; 673 tv->tv_usec = 0; 582 583 return 0; 674 584 } 675 585 … … 677 587 { 678 588 struct timeval tv; 679 gettimeofday(&tv, NULL); 589 if (gettimeofday(&tv, NULL)) 590 return (time_t) -1; 680 591 681 592 if (tloc) … … 720 631 } 721 632 722 /** Get time from broken-down time. 723 * 724 * First normalize the provided broken-down time 725 * (moves all values to their proper bounds) and 726 * then try to calculate the appropriate time_t 727 * representation. 633 /** 634 * This function first normalizes the provided broken-down time 635 * (moves all values to their proper bounds) and then tries to 636 * calculate the appropriate time_t representation. 728 637 * 729 638 * @param tm Broken-down time. 730 * 731 * @return time_t representation of the time. 732 * @return Undefined value on overflow. 733 * 639 * @return time_t representation of the time, undefined value on overflow. 734 640 */ 735 641 time_t mktime(struct tm *tm) … … 737 643 // TODO: take DST flag into account 738 644 // TODO: detect overflow 739 740 normalize_tm_time(tm, 0); 741 return secs_since_epoch(tm); 742 } 743 744 /* 745 * FIXME: This requires POSIX-correct snprintf. 746 * Otherwise it won't work with non-ASCII chars. 747 */ 748 #define APPEND(...) \ 749 { \ 750 consumed = snprintf(ptr, remaining, __VA_ARGS__); \ 751 if (consumed >= remaining) \ 752 return 0; \ 753 \ 754 ptr += consumed; \ 755 remaining -= consumed; \ 756 } 757 758 #define RECURSE(fmt) \ 759 { \ 760 consumed = strftime(ptr, remaining, fmt, tm); \ 761 if (consumed == 0) \ 762 return 0; \ 763 \ 764 ptr += consumed; \ 765 remaining -= consumed; \ 766 } 767 768 #define TO_12H(hour) \ 769 (((hour) > 12) ? ((hour) - 12) : \ 770 (((hour) == 0) ? 12 : (hour))) 771 772 /** Convert time and date to a string. 773 * 774 * @param s Buffer to write string to. 645 646 _normalize_time(tm, 0); 647 return _secs_since_epoch(tm); 648 } 649 650 /** 651 * Convert time and date to a string, based on a specified format and 652 * current locale. 653 * 654 * @param s Buffer to write string to. 775 655 * @param maxsize Size of the buffer. 776 * @param format Format of the output. 777 * @param tm Broken-down time to format. 778 * 656 * @param format Format of the output. 657 * @param tm Broken-down time to format. 779 658 * @return Number of bytes written. 780 *781 659 */ 782 660 size_t strftime(char *restrict s, size_t maxsize, … … 786 664 assert(format != NULL); 787 665 assert(tm != NULL); 788 666 789 667 // TODO: use locale 790 791 668 static const char *wday_abbr[] = { 792 669 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 793 670 }; 794 795 671 static const char *wday[] = { 796 672 "Sunday", "Monday", "Tuesday", "Wednesday", 797 673 "Thursday", "Friday", "Saturday" 798 674 }; 799 800 675 static const char *mon_abbr[] = { 801 676 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 802 677 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 803 678 }; 804 805 679 static const char *mon[] = { 806 680 "January", "February", "March", "April", "May", "June", "July", … … 808 682 }; 809 683 810 if (maxsize < 1) 684 if (maxsize < 1) { 811 685 return 0; 686 } 812 687 813 688 char *ptr = s; … … 815 690 size_t remaining = maxsize; 816 691 692 #define append(...) { \ 693 /* FIXME: this requires POSIX-correct snprintf */ \ 694 /* otherwise it won't work with non-ascii chars */ \ 695 consumed = snprintf(ptr, remaining, __VA_ARGS__); \ 696 if (consumed >= remaining) { \ 697 return 0; \ 698 } \ 699 ptr += consumed; \ 700 remaining -= consumed; \ 701 } 702 703 #define recurse(fmt) { \ 704 consumed = strftime(ptr, remaining, fmt, tm); \ 705 if (consumed == 0) { \ 706 return 0; \ 707 } \ 708 ptr += consumed; \ 709 remaining -= consumed; \ 710 } 711 712 #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \ 713 (((hour) == 0) ? 12 : (hour))) 714 817 715 while (*format != '\0') { 818 716 if (*format != '%') { 819 APPEND("%c", *format);717 append("%c", *format); 820 718 format++; 821 719 continue; … … 823 721 824 722 format++; 825 if ( (*format == '0') || (*format == '+')) {723 if (*format == '0' || *format == '+') { 826 724 // TODO: padding 827 725 format++; 828 726 } 829 830 727 while (isdigit(*format)) { 831 728 // TODO: padding 832 729 format++; 833 730 } 834 835 if ((*format == 'O') || (*format == 'E')) { 731 if (*format == 'O' || *format == 'E') { 836 732 // TODO: locale's alternative format 837 733 format++; … … 840 736 switch (*format) { 841 737 case 'a': 842 APPEND("%s", wday_abbr[tm->tm_wday]); 843 break; 738 append("%s", wday_abbr[tm->tm_wday]); break; 844 739 case 'A': 845 APPEND("%s", wday[tm->tm_wday]); 846 break; 740 append("%s", wday[tm->tm_wday]); break; 847 741 case 'b': 848 APPEND("%s", mon_abbr[tm->tm_mon]); 849 break; 742 append("%s", mon_abbr[tm->tm_mon]); break; 850 743 case 'B': 851 APPEND("%s", mon[tm->tm_mon]); 852 break; 744 append("%s", mon[tm->tm_mon]); break; 853 745 case 'c': 854 746 // TODO: locale-specific datetime format 855 RECURSE("%Y-%m-%d %H:%M:%S"); 856 break; 747 recurse("%Y-%m-%d %H:%M:%S"); break; 857 748 case 'C': 858 APPEND("%02d", (1900 + tm->tm_year) / 100); 859 break; 749 append("%02d", (1900 + tm->tm_year) / 100); break; 860 750 case 'd': 861 APPEND("%02d", tm->tm_mday); 862 break; 751 append("%02d", tm->tm_mday); break; 863 752 case 'D': 864 RECURSE("%m/%d/%y"); 865 break; 753 recurse("%m/%d/%y"); break; 866 754 case 'e': 867 APPEND("%2d", tm->tm_mday); 868 break; 755 append("%2d", tm->tm_mday); break; 869 756 case 'F': 870 RECURSE("%+4Y-%m-%d"); 871 break; 757 recurse("%+4Y-%m-%d"); break; 872 758 case 'g': 873 APPEND("%02d", wbyear(tm) % 100); 874 break; 759 append("%02d", _wbyear(tm) % 100); break; 875 760 case 'G': 876 APPEND("%d", wbyear(tm)); 877 break; 761 append("%d", _wbyear(tm)); break; 878 762 case 'h': 879 RECURSE("%b"); 880 break; 763 recurse("%b"); break; 881 764 case 'H': 882 APPEND("%02d", tm->tm_hour); 883 break; 765 append("%02d", tm->tm_hour); break; 884 766 case 'I': 885 APPEND("%02d", TO_12H(tm->tm_hour)); 886 break; 767 append("%02d", TO_12H(tm->tm_hour)); break; 887 768 case 'j': 888 APPEND("%03d", tm->tm_yday); 889 break; 769 append("%03d", tm->tm_yday); break; 890 770 case 'k': 891 APPEND("%2d", tm->tm_hour); 892 break; 771 append("%2d", tm->tm_hour); break; 893 772 case 'l': 894 APPEND("%2d", TO_12H(tm->tm_hour)); 895 break; 773 append("%2d", TO_12H(tm->tm_hour)); break; 896 774 case 'm': 897 APPEND("%02d", tm->tm_mon); 898 break; 775 append("%02d", tm->tm_mon); break; 899 776 case 'M': 900 APPEND("%02d", tm->tm_min); 901 break; 777 append("%02d", tm->tm_min); break; 902 778 case 'n': 903 APPEND("\n"); 904 break; 779 append("\n"); break; 905 780 case 'p': 906 APPEND("%s", tm->tm_hour < 12 ? "AM" : "PM"); 907 break; 781 append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break; 908 782 case 'P': 909 APPEND("%s", tm->tm_hour < 12 ? "am" : "PM"); 910 break; 783 append("%s", tm->tm_hour < 12 ? "am" : "PM"); break; 911 784 case 'r': 912 RECURSE("%I:%M:%S %p"); 913 break; 785 recurse("%I:%M:%S %p"); break; 914 786 case 'R': 915 RECURSE("%H:%M"); 916 break; 787 recurse("%H:%M"); break; 917 788 case 's': 918 APPEND("%ld", secs_since_epoch(tm)); 919 break; 789 append("%ld", _secs_since_epoch(tm)); break; 920 790 case 'S': 921 APPEND("%02d", tm->tm_sec); 922 break; 791 append("%02d", tm->tm_sec); break; 923 792 case 't': 924 APPEND("\t"); 925 break; 793 append("\t"); break; 926 794 case 'T': 927 RECURSE("%H:%M:%S"); 928 break; 795 recurse("%H:%M:%S"); break; 929 796 case 'u': 930 APPEND("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);797 append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); 931 798 break; 932 799 case 'U': 933 APPEND("%02d", sun_week_number(tm)); 934 break; 800 append("%02d", _sun_week_number(tm)); break; 935 801 case 'V': 936 APPEND("%02d", iso_week_number(tm)); 937 break; 802 append("%02d", _iso_week_number(tm)); break; 938 803 case 'w': 939 APPEND("%d", tm->tm_wday); 940 break; 804 append("%d", tm->tm_wday); break; 941 805 case 'W': 942 APPEND("%02d", mon_week_number(tm)); 943 break; 806 append("%02d", _mon_week_number(tm)); break; 944 807 case 'x': 945 808 // TODO: locale-specific date format 946 RECURSE("%Y-%m-%d"); 947 break; 809 recurse("%Y-%m-%d"); break; 948 810 case 'X': 949 811 // TODO: locale-specific time format 950 RECURSE("%H:%M:%S"); 951 break; 812 recurse("%H:%M:%S"); break; 952 813 case 'y': 953 APPEND("%02d", tm->tm_year % 100); 954 break; 814 append("%02d", tm->tm_year % 100); break; 955 815 case 'Y': 956 APPEND("%d", 1900 + tm->tm_year); 957 break; 816 append("%d", 1900 + tm->tm_year); break; 958 817 case 'z': 959 818 // TODO: timezone … … 963 822 break; 964 823 case '%': 965 APPEND("%%");824 append("%%"); 966 825 break; 967 826 default: 968 827 /* Invalid specifier, print verbatim. */ 969 while (*format != '%') 828 while (*format != '%') { 970 829 format--; 971 972 APPEND("%%");830 } 831 append("%%"); 973 832 break; 974 833 } 975 976 834 format++; 977 835 } 978 836 837 #undef append 838 #undef recurse 839 979 840 return maxsize - remaining; 980 841 } 981 842 982 /** Convert a time value to a broken-down UTC time/ 983 * 984 * @param time Time to convert985 * @param result Structure to store the result to986 * 987 * @return EOK or a negative error code988 * 843 844 /** Converts a time value to a broken-down UTC time 845 * 846 * @param time Time to convert 847 * @param result Structure to store the result to 848 * 849 * @return EOK or a negative error code 989 850 */ 990 851 int time_utc2tm(const time_t time, struct tm *restrict result) 991 852 { 992 853 assert(result != NULL); 993 854 994 855 /* Set result to epoch. */ 995 result->tm_usec = 0;996 856 result->tm_sec = 0; 997 857 result->tm_min = 0; … … 1000 860 result->tm_mon = 0; 1001 861 result->tm_year = 70; /* 1970 */ 1002 1003 if ( normalize_tm_time(result, time) == -1)862 863 if (_normalize_time(result, time) == -1) 1004 864 return EOVERFLOW; 1005 865 1006 866 return EOK; 1007 867 } 1008 868 1009 /** Convert a time value to a NULL-terminated string. 1010 * 1011 * The format is "Wed Jun 30 21:49:08 1993\n" expressed in UTC. 1012 * 1013 * @param time Time to convert. 1014 * @param buf Buffer to store the string to, must be at least 1015 * ASCTIME_BUF_LEN bytes long. 1016 * 1017 * @return EOK or a negative error code. 1018 * 869 /** Converts a time value to a null terminated string of the form 870 * "Wed Jun 30 21:49:08 1993\n" expressed in UTC. 871 * 872 * @param time Time to convert. 873 * @param buf Buffer to store the string to, must be at least 874 * ASCTIME_BUF_LEN bytes long. 875 * 876 * @return EOK or a negative error code. 1019 877 */ 1020 878 int time_utc2str(const time_t time, char *restrict buf) 1021 879 { 1022 struct tm tm; 1023 int ret = time_utc2tm(time, &tm); 1024 if (ret != EOK) 1025 return ret; 1026 1027 time_tm2str(&tm, buf); 880 struct tm t; 881 int r; 882 883 if ((r = time_utc2tm(time, &t)) != EOK) 884 return r; 885 886 time_tm2str(&t, buf); 1028 887 return EOK; 1029 888 } 1030 889 1031 /** Convert broken-down time to a NULL-terminated string. 1032 * 1033 * The format is "Sun Jan 1 00:00:00 1970\n". (Obsolete) 890 891 /** 892 * Converts broken-down time to a string in format 893 * "Sun Jan 1 00:00:00 1970\n". (Obsolete) 1034 894 * 1035 895 * @param timeptr Broken-down time structure. 1036 * @param buf Buffer to store string to, must be at least 1037 * ASCTIME_BUF_LEN bytes long. 1038 * 896 * @param buf Buffer to store string to, must be at least ASCTIME_BUF_LEN 897 * bytes long. 1039 898 */ 1040 899 void time_tm2str(const struct tm *restrict timeptr, char *restrict buf) … … 1042 901 assert(timeptr != NULL); 1043 902 assert(buf != NULL); 1044 903 1045 904 static const char *wday[] = { 1046 905 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 1047 906 }; 1048 1049 907 static const char *mon[] = { 1050 908 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1051 909 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 1052 910 }; 1053 911 1054 912 snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n", 1055 913 wday[timeptr->tm_wday], … … 1060 918 } 1061 919 1062 /** Converts a time value to a broken-down local time. 1063 * 1064 * Time is expressed relative to the user's specified timezone. 1065 * 1066 * @param tv Timeval to convert. 1067 * @param result Structure to store the result to. 1068 * 1069 * @return EOK on success or a negative error code. 1070 * 1071 */ 1072 int time_tv2tm(const struct timeval *tv, struct tm *restrict result) 1073 { 1074 // TODO: Deal with timezones. 1075 // Currently assumes system and all times are in UTC 1076 920 /** 921 * Converts a time value to a broken-down local time, expressed relative 922 * to the user's specified timezone. 923 * 924 * @param timer Time to convert. 925 * @param result Structure to store the result to. 926 * 927 * @return EOK on success or a negative error code. 928 */ 929 int time_local2tm(const time_t time, struct tm *restrict result) 930 { 931 // TODO: deal with timezone 932 // currently assumes system and all times are in GMT 933 1077 934 /* Set result to epoch. */ 1078 result->tm_usec = 0;1079 935 result->tm_sec = 0; 1080 936 result->tm_min = 0; … … 1083 939 result->tm_mon = 0; 1084 940 result->tm_year = 70; /* 1970 */ 1085 1086 if ( normalize_tm_tv(result, tv) == -1)941 942 if (_normalize_time(result, time) == -1) 1087 943 return EOVERFLOW; 1088 944 1089 945 return EOK; 1090 946 } 1091 947 1092 /** Converts a time value to a broken-down local time. 1093 * 1094 * Time is expressed relative to the user's specified timezone. 1095 * 948 /** 949 * Converts the calendar time to a null terminated string 950 * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the 951 * user's specified timezone. 952 * 1096 953 * @param timer Time to convert. 1097 * @param result Structure to store the result to. 1098 * 1099 * @return EOK on success or a negative error code. 1100 * 1101 */ 1102 int time_local2tm(const time_t time, struct tm *restrict result) 1103 { 1104 struct timeval tv = { 1105 .tv_sec = time, 1106 .tv_usec = 0 1107 }; 1108 1109 return time_tv2tm(&tv, result); 1110 } 1111 1112 /** Convert the calendar time to a NULL-terminated string. 1113 * 1114 * The format is "Wed Jun 30 21:49:08 1993\n" expressed relative to the 1115 * user's specified timezone. 1116 * 1117 * @param timer Time to convert. 1118 * @param buf Buffer to store the string to. Must be at least 1119 * ASCTIME_BUF_LEN bytes long. 1120 * 1121 * @return EOK on success or a negative error code. 1122 * 954 * @param buf Buffer to store the string to. Must be at least 955 * ASCTIME_BUF_LEN bytes long. 956 * 957 * @return EOK on success or a negative error code. 1123 958 */ 1124 959 int time_local2str(const time_t time, char *buf) 1125 960 { 1126 961 struct tm loctime; 1127 int ret = time_local2tm(time, &loctime); 1128 if (ret != EOK) 1129 return ret; 1130 962 int r; 963 964 if ((r = time_local2tm(time, &loctime)) != EOK) 965 return r; 966 1131 967 time_tm2str(&loctime, buf); 968 1132 969 return EOK; 1133 970 } 1134 971 1135 /** Calculate the difference between two times, in seconds. 1136 * 972 /** 973 * Calculate the difference between two times, in seconds. 974 * 1137 975 * @param time1 First time. 1138 976 * @param time0 Second time. 1139 * 1140 * @return Time difference in seconds. 1141 * 977 * @return Time in seconds. 1142 978 */ 1143 979 double difftime(time_t time1, time_t time0)
Note:
See TracChangeset
for help on using the changeset viewer.