diff options
-rw-r--r-- | src/include/kernel/timemgr.H | 41 | ||||
-rw-r--r-- | src/include/time.h | 61 | ||||
-rw-r--r-- | src/kernel/timemgr.C | 9 | ||||
-rw-r--r-- | src/lib/syscall_time.C | 28 | ||||
-rw-r--r-- | src/usr/testcore/lib/time.H | 70 |
5 files changed, 207 insertions, 2 deletions
diff --git a/src/include/kernel/timemgr.H b/src/include/kernel/timemgr.H index 4f4bc4413..0590dedff 100644 --- a/src/include/kernel/timemgr.H +++ b/src/include/kernel/timemgr.H @@ -32,36 +32,72 @@ class Scheduler; +/** Struct to hold sleeping tasks in a pqueue */ struct _TimeManager_Delay_t { _TimeManager_Delay_t * next; - _TimeManager_Delay_t * prev; + _TimeManager_Delay_t * prev; uint64_t key; task_t* task; }; +/** @class TimeManager + * @brief Keeps track of sleeping of tasks and conversions between TB and time. + */ class TimeManager { public: enum { + /** Number of time-slices to allow per second. + * + * Context length becomes (1/TIMESLICE_PER_SECOND) sec. + */ TIMESLICE_PER_SEC = 1000, }; + /** Initialize the time subsystem. */ static void init(); + /** Return the number of ticks per time-slice. */ static uint64_t getTimeSliceCount() { return iv_timebaseFreq / TIMESLICE_PER_SEC; }; + /** Returns the value of the processor timebase register. */ static uint64_t getCurrentTimeBase() { return getTB(); }; + /** Converts seconds/nsecs to timebase ticks. + * + * Typically this is used for calculating the number of ticks in an + * interval. + * + * @param[in] i_sec - Number of seconds. + * @param[in] i_nsec - Number of nsecs. + * + * @return Number of timebase ticks. + */ static uint64_t convertSecToTicks(uint64_t i_sec, uint64_t i_nsec); + /** Converts timebase ticks to seconds/nsecs. + * + * @param[in] i_ticks - Number of ticks. + * @param[out] o_sec - Number of seconds. + * @param[out] o_nsec - Number of nsecs. + */ + static void convertTicksToSec(uint64_t i_ticks, + uint64_t& o_sec, uint64_t& o_nsec); + /** Delay (sleep) a task for a length of time. + * + * @param[in] t - Task to delay. + * @param[in] i_sec - Seconds. + * @param[in] i_nsec - Nsecs. + */ static void delayTask(task_t* t, uint64_t i_sec, uint64_t i_nsec); + /** Checks the sleep queue to determine if any tasks should be woken. */ static void checkReleaseTasks(Scheduler* s); protected: @@ -72,9 +108,10 @@ class TimeManager void _init(); void _delayTask(task_t* t, uint64_t i_sec, uint64_t i_nsec); void _checkReleaseTasks(Scheduler* s); - + Util::Locked::PQueue<_TimeManager_Delay_t, uint64_t> iv_taskList[KERNEL_MAX_SUPPORTED_CPUS]; + /** Frequency of the timebase register in Hz. (ticks per second) */ static uint64_t iv_timebaseFreq; }; diff --git a/src/include/time.h b/src/include/time.h new file mode 100644 index 000000000..cc3a9e4bf --- /dev/null +++ b/src/include/time.h @@ -0,0 +1,61 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/include/time.h $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __TIME_H +#define __TIME_H + +#include <stdint.h> + +// POSIX structure for time (sec / nsec pairs). +struct timespec +{ + uint64_t tv_sec; + uint64_t tv_nsec; +}; +typedef struct timespec timespec_t; + +// POSIX clock IDs. +typedef enum +{ + CLOCK_REALTIME = 0, + CLOCK_MONOTONIC = 1 +} clockid_t; + +/** @fn clock_gettime + * @brief Reads the clock value from a POSIX clock. + * + * @note Currently, we only support CLOCK_MONOTONIC. + * CLOCK_REALTIME requires synchronization of the timebase with the FSP + * RTC. + * + * @param[in] clk_id - The clock ID to read. + * @param[out] tp - The timespec struct to store the clock value in. + * + * @return 0 or -(errno). + * @retval 0 - SUCCESS. + * @retval -EINVAL - Invalid clock requested. + * @retval -EFAULT - NULL ptr given for timespec struct. + * + */ +int clock_gettime(clockid_t clk_id, timespec_t* tp); + +#endif diff --git a/src/kernel/timemgr.C b/src/kernel/timemgr.C index 896871a4d..b6be8cb90 100644 --- a/src/kernel/timemgr.C +++ b/src/kernel/timemgr.C @@ -49,6 +49,15 @@ uint64_t TimeManager::convertSecToTicks(uint64_t i_sec, uint64_t i_nsec) return result; } +void TimeManager::convertTicksToSec(uint64_t i_ticks, + uint64_t& o_sec, uint64_t& o_nsec) +{ + o_sec = i_ticks / iv_timebaseFreq; + + o_nsec = (i_ticks - (o_sec * iv_timebaseFreq)) * 1000; + o_nsec /= (iv_timebaseFreq / 1000000); +} + void TimeManager::delayTask(task_t* t, uint64_t i_sec, uint64_t i_nsec) { Singleton<TimeManager>::instance()._delayTask(t,i_sec,i_nsec); diff --git a/src/lib/syscall_time.C b/src/lib/syscall_time.C index d4ea6d0a7..819b605b0 100644 --- a/src/lib/syscall_time.C +++ b/src/lib/syscall_time.C @@ -20,8 +20,11 @@ // Origin: 30 // // IBM_PROLOG_END +#include <time.h> #include <sys/time.h> #include <sys/syscall.h> +#include <errno.h> +#include <kernel/timemgr.H> using namespace Systemcalls; @@ -29,3 +32,28 @@ void nanosleep(uint64_t sec, uint64_t nsec) { _syscall2(TIME_NANOSLEEP, (void*)sec, (void*)nsec); } + +int clock_gettime(clockid_t clk_id, timespec_t* tp) +{ + if (unlikely(NULL == tp)) { return -EFAULT; } + + int rc = 0; + + switch(clk_id) + { + case CLOCK_REALTIME: // TODO: Need a message to the FSP to get the + // real-time. + rc = -EINVAL; + break; + + case CLOCK_MONOTONIC: + TimeManager::convertTicksToSec(getTB(), tp->tv_sec, tp->tv_nsec); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} diff --git a/src/usr/testcore/lib/time.H b/src/usr/testcore/lib/time.H new file mode 100644 index 000000000..895d2884e --- /dev/null +++ b/src/usr/testcore/lib/time.H @@ -0,0 +1,70 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/testcore/lib/time.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END + +#ifndef __TESTCORE_LIB_TIME_H +#define __TESTCORE_LIB_TIME_H + +#include <time.h> +#include <sys/time.h> +#include <errno.h> + +/** @file time.H + * @brief Test cases for the time / sleep sub-system. + */ + +class TimeTest : public CxxTest::TestSuite +{ + public: + /** + * Tests for the clock_gettime POSIX function. + */ + void testClockGetTime() + { + timespec_t first, second; + + if (-EINVAL != clock_gettime(CLOCK_REALTIME, &first)) + { + TS_FAIL("CLOCK_REALTIME not implemented, but no EINVAL"); + } + + if (0 != clock_gettime(CLOCK_MONOTONIC, &first)) + { + TS_FAIL("Unable to read monotonic clock"); + } + + nanosleep(0,1); + + if (0 != clock_gettime(CLOCK_MONOTONIC, &second)) + { + TS_FAIL("Unable to read monotonic clock"); + } + + if ((second.tv_sec <= first.tv_sec) && + (second.tv_nsec <= first.tv_nsec)) + { + TS_FAIL("Monotonic clock is not increasing."); + } + } +}; + +#endif |