Serenity Operating System
at master 503 lines 16 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/DateConstants.h> 8#include <AK/DeprecatedString.h> 9#include <AK/StringBuilder.h> 10#include <AK/Time.h> 11#include <Kernel/API/TimePage.h> 12#include <LibTimeZone/TimeZone.h> 13#include <assert.h> 14#include <bits/pthread_cancel.h> 15#include <errno.h> 16#include <limits.h> 17#include <stdio.h> 18#include <string.h> 19#include <sys/time.h> 20#include <sys/times.h> 21#include <syscall.h> 22#include <time.h> 23#include <utime.h> 24 25extern "C" { 26 27static constexpr char const* __utc = "UTC"; 28static StringView __tzname { __utc, __builtin_strlen(__utc) }; 29static char __tzname_standard[TZNAME_MAX]; 30static char __tzname_daylight[TZNAME_MAX]; 31 32long timezone = 0; 33long altzone = 0; 34char* tzname[2] = { const_cast<char*>(__utc), const_cast<char*>(__utc) }; 35int daylight = 0; 36 37time_t time(time_t* tloc) 38{ 39 struct timeval tv; 40 struct timezone tz; 41 if (gettimeofday(&tv, &tz) < 0) 42 return (time_t)-1; 43 if (tloc) 44 *tloc = tv.tv_sec; 45 return tv.tv_sec; 46} 47 48int adjtime(const struct timeval* delta, struct timeval* old_delta) 49{ 50 int rc = syscall(SC_adjtime, delta, old_delta); 51 __RETURN_WITH_ERRNO(rc, rc, -1); 52} 53 54int gettimeofday(struct timeval* __restrict__ tv, void* __restrict__) 55{ 56 if (!tv) { 57 errno = EFAULT; 58 return -1; 59 } 60 61 struct timespec ts = {}; 62 if (clock_gettime(CLOCK_REALTIME_COARSE, &ts) < 0) 63 return -1; 64 65 TIMESPEC_TO_TIMEVAL(tv, &ts); 66 return 0; 67} 68 69int settimeofday(struct timeval* __restrict__ tv, void* __restrict__) 70{ 71 if (!tv) { 72 errno = EFAULT; 73 return -1; 74 } 75 76 timespec ts; 77 TIMEVAL_TO_TIMESPEC(tv, &ts); 78 return clock_settime(CLOCK_REALTIME, &ts); 79} 80 81int utimes(char const* pathname, const struct timeval times[2]) 82{ 83 if (!times) { 84 return utime(pathname, nullptr); 85 } 86 // FIXME: implement support for tv_usec in the utime (or a new) syscall 87 utimbuf buf = { times[0].tv_sec, times[1].tv_sec }; 88 return utime(pathname, &buf); 89} 90 91char* ctime(time_t const* t) 92{ 93 return asctime(localtime(t)); 94} 95 96char* ctime_r(time_t const* t, char* buf) 97{ 98 struct tm tm_buf; 99 return asctime_r(localtime_r(t, &tm_buf), buf); 100} 101 102static int const __seconds_per_day = 60 * 60 * 24; 103 104static bool is_valid_time(time_t timestamp) 105{ 106 // Note: these correspond to the number of seconds from epoch to the dates "Jan 1 00:00:00 -2147483648" and "Dec 31 23:59:59 2147483647", 107 // respectively, which are the smallest and biggest representable dates without overflowing tm->tm_year, if it is an int. 108 constexpr time_t smallest_possible_time = -67768040609740800; 109 constexpr time_t biggest_possible_time = 67768036191676799; 110 111 return (timestamp >= smallest_possible_time) && (timestamp <= biggest_possible_time); 112} 113 114static struct tm* time_to_tm(struct tm* tm, time_t t, StringView time_zone) 115{ 116 if (!is_valid_time(t)) { 117 errno = EOVERFLOW; 118 return nullptr; 119 } 120 121 if (auto offset = TimeZone::get_time_zone_offset(time_zone, AK::Time::from_seconds(t)); offset.has_value()) { 122 tm->tm_isdst = offset->in_dst == TimeZone::InDST::Yes; 123 t += offset->seconds; 124 } 125 126 int year = 1970; 127 for (; t >= days_in_year(year) * __seconds_per_day; ++year) 128 t -= days_in_year(year) * __seconds_per_day; 129 for (; t < 0; --year) 130 t += days_in_year(year - 1) * __seconds_per_day; 131 tm->tm_year = year - 1900; 132 133 VERIFY(t >= 0); 134 int days = t / __seconds_per_day; 135 tm->tm_yday = days; 136 int remaining = t % __seconds_per_day; 137 tm->tm_sec = remaining % 60; 138 remaining /= 60; 139 tm->tm_min = remaining % 60; 140 tm->tm_hour = remaining / 60; 141 142 int month; 143 for (month = 1; month < 12 && days >= days_in_month(year, month); ++month) 144 days -= days_in_month(year, month); 145 146 tm->tm_mday = days + 1; 147 tm->tm_wday = day_of_week(year, month, tm->tm_mday); 148 tm->tm_mon = month - 1; 149 150 return tm; 151} 152 153static time_t tm_to_time(struct tm* tm, StringView time_zone) 154{ 155 // "The original values of the tm_wday and tm_yday components of the structure are ignored, 156 // and the original values of the other components are not restricted to the ranges described in <time.h>. 157 // [...] 158 // Upon successful completion, the values of the tm_wday and tm_yday components of the structure shall be set appropriately, 159 // and the other components are set to represent the specified time since the Epoch, 160 // but with their values forced to the ranges indicated in the <time.h> entry; 161 // the final value of tm_mday shall not be set until tm_mon and tm_year are determined." 162 163 tm->tm_year += tm->tm_mon / 12; 164 tm->tm_mon %= 12; 165 if (tm->tm_mon < 0) { 166 tm->tm_year--; 167 tm->tm_mon += 12; 168 } 169 170 tm->tm_yday = day_of_year(1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday); 171 time_t days_since_epoch = years_to_days_since_epoch(1900 + tm->tm_year) + tm->tm_yday; 172 auto timestamp = ((days_since_epoch * 24 + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec; 173 174 if (tm->tm_isdst < 0) { 175 if (auto offset = TimeZone::get_time_zone_offset(time_zone, AK::Time::from_seconds(timestamp)); offset.has_value()) 176 timestamp -= offset->seconds; 177 } else { 178 auto index = tm->tm_isdst == 0 ? 0 : 1; 179 180 if (auto offsets = TimeZone::get_named_time_zone_offsets(time_zone, AK::Time::from_seconds(timestamp)); offsets.has_value()) 181 timestamp -= offsets->at(index).seconds; 182 } 183 184 if (!is_valid_time(timestamp)) { 185 errno = EOVERFLOW; 186 return -1; 187 } 188 189 return timestamp; 190} 191 192time_t mktime(struct tm* tm) 193{ 194 tzset(); 195 return tm_to_time(tm, __tzname); 196} 197 198struct tm* localtime(time_t const* t) 199{ 200 tzset(); 201 202 static struct tm tm_buf; 203 return localtime_r(t, &tm_buf); 204} 205 206struct tm* localtime_r(time_t const* t, struct tm* tm) 207{ 208 if (!t) 209 return nullptr; 210 211 return time_to_tm(tm, *t, __tzname); 212} 213 214time_t timegm(struct tm* tm) 215{ 216 tm->tm_isdst = 0; 217 return tm_to_time(tm, { __utc, __builtin_strlen(__utc) }); 218} 219 220struct tm* gmtime(time_t const* t) 221{ 222 static struct tm tm_buf; 223 return gmtime_r(t, &tm_buf); 224} 225 226struct tm* gmtime_r(time_t const* t, struct tm* tm) 227{ 228 if (!t) 229 return nullptr; 230 return time_to_tm(tm, *t, { __utc, __builtin_strlen(__utc) }); 231} 232 233char* asctime(const struct tm* tm) 234{ 235 static char buffer[69]; 236 return asctime_r(tm, buffer); 237} 238 239char* asctime_r(const struct tm* tm, char* buffer) 240{ 241 // Spec states buffer must be at least 26 bytes. 242 constexpr size_t assumed_len = 26; 243 size_t filled_size = strftime(buffer, assumed_len, "%a %b %e %T %Y\n", tm); 244 245 // If the buffer was not large enough, set EOVERFLOW and return null. 246 if (filled_size == 0) { 247 errno = EOVERFLOW; 248 return nullptr; 249 } 250 251 return buffer; 252} 253 254// FIXME: Some formats are not supported. 255size_t strftime(char* destination, size_t max_size, char const* format, const struct tm* tm) 256{ 257 tzset(); 258 259 StringBuilder builder { max_size }; 260 261 int const format_len = strlen(format); 262 for (int i = 0; i < format_len; ++i) { 263 if (format[i] != '%') { 264 builder.append(format[i]); 265 } else { 266 if (++i >= format_len) 267 return 0; 268 269 switch (format[i]) { 270 case 'a': 271 builder.append(short_day_names[tm->tm_wday]); 272 break; 273 case 'A': 274 builder.append(long_day_names[tm->tm_wday]); 275 break; 276 case 'b': 277 builder.append(short_month_names[tm->tm_mon]); 278 break; 279 case 'B': 280 builder.append(long_month_names[tm->tm_mon]); 281 break; 282 case 'C': 283 builder.appendff("{:02}", (tm->tm_year + 1900) / 100); 284 break; 285 case 'd': 286 builder.appendff("{:02}", tm->tm_mday); 287 break; 288 case 'D': 289 builder.appendff("{:02}/{:02}/{:02}", tm->tm_mon + 1, tm->tm_mday, (tm->tm_year + 1900) % 100); 290 break; 291 case 'e': 292 builder.appendff("{:2}", tm->tm_mday); 293 break; 294 case 'h': 295 builder.append(short_month_names[tm->tm_mon]); 296 break; 297 case 'H': 298 builder.appendff("{:02}", tm->tm_hour); 299 break; 300 case 'I': { 301 int display_hour = tm->tm_hour % 12; 302 if (display_hour == 0) 303 display_hour = 12; 304 builder.appendff("{:02}", display_hour); 305 break; 306 } 307 case 'j': 308 builder.appendff("{:03}", tm->tm_yday + 1); 309 break; 310 case 'm': 311 builder.appendff("{:02}", tm->tm_mon + 1); 312 break; 313 case 'M': 314 builder.appendff("{:02}", tm->tm_min); 315 break; 316 case 'n': 317 builder.append('\n'); 318 break; 319 case 'p': 320 builder.append(tm->tm_hour < 12 ? "AM"sv : "PM"sv); 321 break; 322 case 'r': { 323 int display_hour = tm->tm_hour % 12; 324 if (display_hour == 0) 325 display_hour = 12; 326 builder.appendff("{:02}:{:02}:{:02} {}", display_hour, tm->tm_min, tm->tm_sec, tm->tm_hour < 12 ? "AM" : "PM"); 327 break; 328 } 329 case 'R': 330 builder.appendff("{:02}:{:02}", tm->tm_hour, tm->tm_min); 331 break; 332 case 'S': 333 builder.appendff("{:02}", tm->tm_sec); 334 break; 335 case 't': 336 builder.append('\t'); 337 break; 338 case 'T': 339 builder.appendff("{:02}:{:02}:{:02}", tm->tm_hour, tm->tm_min, tm->tm_sec); 340 break; 341 case 'u': 342 builder.appendff("{}", tm->tm_wday ? tm->tm_wday : 7); 343 break; 344 case 'U': { 345 int const wday_of_year_beginning = (tm->tm_wday + 6 * tm->tm_yday) % 7; 346 int const week_number = (tm->tm_yday + wday_of_year_beginning) / 7; 347 builder.appendff("{:02}", week_number); 348 break; 349 } 350 case 'V': { 351 int const wday_of_year_beginning = (tm->tm_wday + 6 + 6 * tm->tm_yday) % 7; 352 int week_number = (tm->tm_yday + wday_of_year_beginning) / 7 + 1; 353 if (wday_of_year_beginning > 3) { 354 if (tm->tm_yday >= 7 - wday_of_year_beginning) 355 --week_number; 356 else { 357 int const days_of_last_year = days_in_year(tm->tm_year + 1900 - 1); 358 int const wday_of_last_year_beginning = (wday_of_year_beginning + 6 * days_of_last_year) % 7; 359 week_number = (days_of_last_year + wday_of_last_year_beginning) / 7 + 1; 360 if (wday_of_last_year_beginning > 3) 361 --week_number; 362 } 363 } 364 builder.appendff("{:02}", week_number); 365 break; 366 } 367 case 'w': 368 builder.appendff("{}", tm->tm_wday); 369 break; 370 case 'W': { 371 int const wday_of_year_beginning = (tm->tm_wday + 6 + 6 * tm->tm_yday) % 7; 372 int const week_number = (tm->tm_yday + wday_of_year_beginning) / 7; 373 builder.appendff("{:02}", week_number); 374 break; 375 } 376 case 'y': 377 builder.appendff("{:02}", (tm->tm_year + 1900) % 100); 378 break; 379 case 'Y': 380 builder.appendff("{}", tm->tm_year + 1900); 381 break; 382 case '%': 383 builder.append('%'); 384 break; 385 default: 386 return 0; 387 } 388 } 389 if (builder.length() + 1 > max_size) 390 return 0; 391 } 392 393 auto str = builder.to_deprecated_string(); 394 bool fits = str.copy_characters_to_buffer(destination, max_size); 395 return fits ? str.length() : 0; 396} 397 398void tzset() 399{ 400 __tzname = TimeZone::current_time_zone(); 401 402 auto set_default_values = []() { 403 timezone = 0; 404 altzone = 0; 405 daylight = 0; 406 __tzname = StringView { __utc, __builtin_strlen(__utc) }; 407 tzname[0] = const_cast<char*>(__utc); 408 tzname[1] = const_cast<char*>(__utc); 409 }; 410 411 if (auto offsets = TimeZone::get_named_time_zone_offsets(__tzname, AK::Time::now_realtime()); offsets.has_value()) { 412 if (!offsets->at(0).name.copy_characters_to_buffer(__tzname_standard, TZNAME_MAX)) 413 return set_default_values(); 414 if (!offsets->at(1).name.copy_characters_to_buffer(__tzname_daylight, TZNAME_MAX)) 415 return set_default_values(); 416 417 // timezone and altzone are seconds west of UTC, i.e. the offsets are negated. 418 timezone = -offsets->at(0).seconds; 419 altzone = -offsets->at(1).seconds; 420 daylight = timezone != altzone; 421 tzname[0] = __tzname_standard; 422 tzname[1] = __tzname_daylight; 423 } else { 424 set_default_values(); 425 } 426} 427 428clock_t clock() 429{ 430 struct tms tms; 431 times(&tms); 432 return tms.tms_utime + tms.tms_stime; 433} 434 435static Kernel::TimePage* get_kernel_time_page() 436{ 437 static Kernel::TimePage* s_kernel_time_page; 438 // FIXME: Thread safety 439 if (!s_kernel_time_page) { 440 auto rc = syscall(SC_map_time_page); 441 if ((int)rc < 0 && (int)rc > -EMAXERRNO) { 442 errno = -(int)rc; 443 return nullptr; 444 } 445 s_kernel_time_page = (Kernel::TimePage*)rc; 446 } 447 return s_kernel_time_page; 448} 449 450int clock_gettime(clockid_t clock_id, struct timespec* ts) 451{ 452 if (Kernel::time_page_supports(clock_id)) { 453 if (!ts) { 454 errno = EFAULT; 455 return -1; 456 } 457 458 if (auto* kernel_time_page = get_kernel_time_page()) { 459 u32 update_iteration; 460 do { 461 update_iteration = AK::atomic_load(&kernel_time_page->update1, AK::memory_order_acquire); 462 *ts = kernel_time_page->clocks[clock_id]; 463 } while (update_iteration != AK::atomic_load(&kernel_time_page->update2, AK::memory_order_acquire)); 464 return 0; 465 } 466 } 467 468 int rc = syscall(SC_clock_gettime, clock_id, ts); 469 __RETURN_WITH_ERRNO(rc, rc, -1); 470} 471 472int clock_settime(clockid_t clock_id, struct timespec* ts) 473{ 474 int rc = syscall(SC_clock_settime, clock_id, ts); 475 __RETURN_WITH_ERRNO(rc, rc, -1); 476} 477 478int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* requested_sleep, struct timespec* remaining_sleep) 479{ 480 __pthread_maybe_cancel(); 481 482 Syscall::SC_clock_nanosleep_params params { clock_id, flags, requested_sleep, remaining_sleep }; 483 int rc = syscall(SC_clock_nanosleep, &params); 484 __RETURN_WITH_ERRNO(rc, rc, -1); 485} 486 487int nanosleep(const struct timespec* requested_sleep, struct timespec* remaining_sleep) 488{ 489 return clock_nanosleep(CLOCK_REALTIME, 0, requested_sleep, remaining_sleep); 490} 491 492int clock_getres(clockid_t clock_id, struct timespec* result) 493{ 494 Syscall::SC_clock_getres_params params { clock_id, result }; 495 int rc = syscall(SC_clock_getres, &params); 496 __RETURN_WITH_ERRNO(rc, rc, -1); 497} 498 499double difftime(time_t t1, time_t t0) 500{ 501 return (double)(t1 - t0); 502} 503}