/*
* Copyright (c) 2011 Petr Koupy
* Copyright (c) 2011 Jiri Zarevucky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @addtogroup libposix
* @{
*/
/** @file Time measurement support.
*/
#include "internal/common.h"
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <assert.h>
#include <fibril.h>
#include <stdlib.h>
#include <task.h>
#include <stddef.h>
// TODO: test everything in this file
/*
* In some places in this file, phrase "normalized broken-down time" is used.
* This means time broken down to components (year, month, day, hour, min, sec),
* in which every component is in its proper bounds. Non-normalized time could
* e.g. be 2011-54-5 29:13:-5, which would semantically mean start of year 2011
* + 53 months + 4 days + 29 hours + 13 minutes - 5 seconds.
*/
int posix_daylight;
long posix_timezone;
char *posix_tzname[2];
/**
* Set timezone conversion information.
*/
void tzset(void)
{
// TODO: read environment
posix_tzname[0] = (char *) "GMT";
posix_tzname[1] = (char *) "GMT";
posix_daylight = 0;
posix_timezone = 0;
}
/**
* Converts a time value to a broken-down UTC time.
*
* @param timer Time to convert.
* @param result Structure to store the result to.
* @return Value of result on success, NULL on overflow.
*/
struct tm *gmtime_r(const time_t *restrict timer,
struct tm *restrict result)
{
if (failed(time_utc2tm(*timer, result))) {
return NULL;
}
return result;
}
/**
* Converts a time value to a broken-down UTC time.
* (non reentrant version)
*
* @param timep Time to convert
* @return Pointer to a statically allocated structure that stores
* the result, NULL in case of error.
*/
struct tm *gmtime(const time_t *restrict timep)
{
static struct tm result;
return gmtime_r(timep, &result);
}
/**
* Converts a time value to a broken-down local time.
*
* @param timer Time to convert.
* @param result Structure to store the result to.
* @return Value of result on success, NULL on overflow.
*/
struct tm *localtime_r(const time_t *restrict timer,
struct tm *restrict result)
{
// TODO: deal with timezone
// currently assumes system and all times are in GMT
return gmtime_r(timer, result);
}
/**
* Converts a time value to a broken-down local time.
* (non reentrant version)
*
* @param timep Time to convert.
* @return Pointer to a statically allocated structure that stores
* the result, NULL in case of error.
*/
struct tm *localtime(const time_t *restrict timep)
{
static struct tm result;
return localtime_r(timep, &result);
}
/**
* Converts broken-down time to a string in format
* "Sun Jan 1 00:00:00 1970\n". (Obsolete)
*
* @param timeptr Broken-down time structure.
* @param buf Buffer to store string to, must be at least ASCTIME_BUF_LEN
* bytes long.
* @return Value of buf.
*/
char *asctime_r(const struct tm *restrict timeptr,
char *restrict buf)
{
time_tm2str(timeptr, buf);
return buf;
}
/**
* Convers broken-down time to a string in format
* "Sun Jan 1 00:00:00 1970\n". (Obsolete)
* (non reentrant version)
*
* @param timeptr Broken-down time structure.
* @return Pointer to a statically allocated buffer that stores
* the result, NULL in case of error.
*/
char *asctime(const struct tm *restrict timeptr)
{
static char buf[ASCTIME_BUF_LEN];
return asctime_r(timeptr, buf);
}
/**
* Converts the calendar time to a string in format
* "Sun Jan 1 00:00:00 1970\n" (Obsolete)
*
* @param timer Time to convert.
* @param buf Buffer to store string to. Must be at least ASCTIME_BUF_LEN
* bytes long.
* @return Pointer to buf on success, NULL on failure.
*/
char *ctime_r(const time_t *timer, char *buf)
{
if (failed(time_local2str(*timer, buf))) {
return NULL;
}
return buf;
}
/**
* Converts the calendar time to a string in format
* "Sun Jan 1 00:00:00 1970\n" (Obsolete)
* (non reentrant version)
*
* @param timep Time to convert.
* @return Pointer to a statically allocated buffer that stores
* the result, NULL in case of error.
*/
char *ctime(const time_t *timep)
{
static char buf[ASCTIME_BUF_LEN];
return ctime_r(timep, buf);
}
/**
* Get clock resolution. Only CLOCK_REALTIME is supported.
*
* @param clock_id Clock ID.
* @param res Pointer to the variable where the resolution is to be written.
* @return 0 on success, -1 with errno set on failure.
*/
int clock_getres(clockid_t clock_id, struct timespec *res)
{
assert(res != NULL);
switch (clock_id) {
case CLOCK_REALTIME:
res->tv_sec = 0;
res->tv_nsec = USEC2NSEC(1); /* Microsecond resolution. */
return 0;
default:
errno = EINVAL;
return -1;
}
}
/**
* Get time. Only CLOCK_REALTIME is supported.
*
* @param clock_id ID of the clock to query.
* @param tp Pointer to the variable where the time is to be written.
* @return 0 on success, -1 with errno on failure.
*/
int clock_gettime(clockid_t clock_id, struct timespec *tp)
{
struct timeval tv;
assert(tp != NULL);
switch (clock_id) {
case CLOCK_REALTIME:
gettimeofday(&tv, NULL);
tp->tv_sec = tv.tv_sec;
tp->tv_nsec = USEC2NSEC(tv.tv_usec);
return 0;
default:
errno = EINVAL;
return -1;
}
}
/**
* Set time on a specified clock. As HelenOS doesn't support this yet,
* this function always fails.
*
* @param clock_id ID of the clock to set.
* @param tp Time to set.
* @return 0 on success, -1 with errno on failure.
*/
int clock_settime(clockid_t clock_id,
const struct timespec *tp)
{
assert(tp != NULL);
switch (clock_id) {
case CLOCK_REALTIME:
// TODO: setting clock
// FIXME: HelenOS doesn't actually support hardware
// clock yet
errno = EPERM;
return -1;
default:
errno = EINVAL;
return -1;
}
}
/**
* Sleep on a specified clock.
*
* @param clock_id ID of the clock to sleep on (only CLOCK_REALTIME supported).
* @param flags Flags (none supported).
* @param rqtp Sleep time.
* @param rmtp Remaining time is written here if sleep is interrupted.
* @return 0 on success, -1 with errno set on failure.
*/
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *rqtp, struct timespec *rmtp)
{
assert(rqtp != NULL);
assert(rmtp != NULL);
switch (clock_id) {
case CLOCK_REALTIME:
// TODO: interruptible sleep
if (rqtp->tv_sec != 0) {
fibril_sleep(rqtp->tv_sec);
}
if (rqtp->tv_nsec != 0) {
fibril_usleep(NSEC2USEC(rqtp->tv_nsec));
}
return 0;
default:
errno = EINVAL;
return -1;
}
}
int gettimeofday(struct timeval *tv, void *tz)
{
struct timespec ts;
getrealtime(&ts);
tv->tv_sec = ts.tv_sec;
tv->tv_usec = NSEC2USEC(ts.tv_nsec);
return 0;
}
/** @}
*/