⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 time.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      time.cxx
//
//      POSIX time functions implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):           nickg
// Contributors:        nickg
// Date:                2000-03-27
// Purpose:             POSIX time functions implementation
// Description:         This file contains the implementation of the POSIX time
//                      functions.
//              
//              
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/posix.h>

#ifdef CYGPKG_POSIX_CLOCKS

#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>

#include <cyg/kernel/ktypes.h>          // base kernel types
#include <cyg/infra/cyg_trac.h>         // tracing macros
#include <cyg/infra/cyg_ass.h>          // assertion macros

#include "pprivate.h"                   // POSIX private header

#include <time.h>                       // our header

#include <cyg/kernel/thread.hxx>
#include <cyg/kernel/clock.hxx>

#include <cyg/kernel/thread.inl>
#include <cyg/kernel/clock.inl>

// -------------------------------------------------------------------------
// Internal definitions

// Handle entry to a pthread package function. 
#define TIME_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );

// Do a time package defined return. This requires the error code
// to be placed in errno, and if it is non-zero, -1 returned as the
// result of the function. This also gives us a place to put any
// generic tidyup handling needed for things like signal delivery and
// cancellation.
#define TIME_RETURN(err)                        \CYG_MACRO_START                                 \    int __retval = 0;                           \    if( err != 0 ) __retval = -1, errno = err;  \    CYG_REPORT_RETVAL( __retval );              \    return __retval;                            \CYG_MACRO_END

//==========================================================================
// Timer control structures

#ifdef CYGPKG_POSIX_TIMERS
typedef struct
{
    timer_t             id;             // id value for checking
    Cyg_Alarm           *alarm;         // eCos alarm object
    cyg_bool            armed;          // is alarm enabled?
    cyg_bool            pending;        // is expiry pending?
    int                 overrun;        // Overrun count
    struct sigevent     sigev;          // Sigevent to raise on expiry
    
    // Space for alarm object
    cyg_uint8           alarm_obj[sizeof(Cyg_Alarm)];
    
} posix_timer;

// Mutex for controlling access to shared data structures
static Cyg_Mutex timer_mutex CYGBLD_POSIX_INIT;

// Array of timer objects
static posix_timer timer_table[_POSIX_TIMER_MAX];

// Index of next timer to allocate from array
static int timer_next = 0;

// This is used to make timer_t values unique even when reusing
// a table slot. This allows _POSIX_TIMER_MAX to range
// up to 1024.
#define TIMER_ID_COOKIE_INC 0x00000400
#define TIMER_ID_COOKIE_MASK (TIMER_ID_COOKIE_INC-1)
static timer_t timer_id_cookie = TIMER_ID_COOKIE_INC;

#endif // ifdef CYGPKG_POSIX_TIMERS

//-----------------------------------------------------------------------------
// new operator to allow us to invoke the constructor on
// posix_timer.alarm_obj.

inline void *operator new(size_t size,  cyg_uint8 *ptr) { return (void *)ptr; };

//==========================================================================
// Time conversion variables
// These are used to interconvert between ticks and POSIX timespecs.

// Converters from sec and ns to ticks
static struct Cyg_Clock::converter ns_converter, sec_converter;

// Converters from ticks to sec and ns
static struct Cyg_Clock::converter ns_inverter, sec_inverter;

// tickns is the number of nanoseconds per tick.
static cyg_tick_count tickns;

static cyg_bool converters_initialized = false;

//==========================================================================
// Local functions

static void init_converters()
{
    if( !converters_initialized )
    {

        // Create the converters we need.
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1, &ns_converter );
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
        Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1, &ns_inverter );    
        Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1000000000, &sec_inverter );

        tickns = Cyg_Clock::convert( 1, &ns_inverter );
            
        converters_initialized = true;
    }
}

static cyg_bool valid_timespec( const struct timespec *tp )
{
    // Fail a NULL pointer
    if( tp == NULL ) return false;

    // Fail illegal nanosecond values
    if( tp->tv_nsec < 0 || tp->tv_nsec > 1000000000 )
        return false;

    return true;
}

externC cyg_tick_count cyg_timespec_to_ticks( const struct timespec *tp,
                                              cyg_bool roundup)
{
    init_converters();

    // Short circuit zero timespecs
    if( tp->tv_sec == 0 && tp->tv_nsec == 0 )
    {
        return 0;
    }
        
    // Convert the seconds field to ticks.
    cyg_tick_count ticks = Cyg_Clock::convert( tp->tv_sec, &sec_converter );

    if( roundup )
    {
        // Convert the nanoseconds. We add (tickns-1) to round the value up
        // to the next whole tick.

        ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec+tickns-1, &ns_converter );    
    }
    else
    {
        // Convert the nanoseconds. This will round down to nearest whole tick.
        ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec, &ns_converter );
    }

    return ticks;
}

externC void cyg_ticks_to_timespec( cyg_tick_count ticks, struct timespec *tp )
{
    init_converters();

    // short circuit zero ticks values
    if( ticks == 0 )
    {
        tp->tv_sec = 0;
        tp->tv_nsec = 0;
        return;
    }

    // Convert everything to nanoseconds with a long long. For 64-bits,
    // this is safe for 544 years. We'll think about it more closer to
    // the time...

    unsigned long long nsecs = Cyg_Clock::convert( ticks, &ns_inverter );

    tp->tv_sec = (long)(nsecs / 1000000000ll);
    tp->tv_nsec = (long)(nsecs % 1000000000ll);

    CYG_POSTCONDITION(valid_timespec(tp), "Failed to make valid timespec!");
}

//==========================================================================
// Startup routine.

externC void cyg_posix_clock_start()
{
    init_converters();
}

#ifdef CYGPKG_POSIX_TIMERS
//==========================================================================
// Alarm action routine
// This is called each time an alarm set up by a timer expires.

static void alarm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data )
{
    posix_timer *timer = (posix_timer *)data;

    if( timer->pending )
    {
        // If the pending flag is already set, count an overrun and
        // do not bother to try and deliver the expiry.
        
        timer->overrun++;
    }
    else
    {
        if( timer->sigev.sigev_notify == SIGEV_SIGNAL )
        {
            // Set the expiry pending and wake a thread to
            // deliver the signal.
        
            timer->pending = true;
    
            sigset_t mask;
            sigemptyset( &mask );
            sigaddset( &mask, timer->sigev.sigev_signo );
            cyg_posix_signal_sigwait();
            cyg_posix_pthread_release_thread( &mask );
        }
        else if( timer->sigev.sigev_notify == SIGEV_THREAD )
        {
            // Thread style notification
            // FIXME: implement SIGEV_THREAD
        }
        // else do nothing
    }
}

//==========================================================================
// Timer ASR routine

externC void cyg_posix_timer_asr( pthread_info *self )
{

    // Loop over the timers looking for any that have an
    // expiry pending and call cyg_sigqueue() for each.
    
    for( int i = 0; i < _POSIX_TIMER_MAX; i++ )
    {
        posix_timer *timer = &timer_table[i];

        if( timer->id != 0 && timer->pending )
        {
            timer->pending = false;
                
            // Call into signal subsystem...
            cyg_sigqueue( &timer->sigev, SI_TIMER );

            timer->overrun = 0;
        }
    }
}

#endif // ifdef CYGPKG_POSIX_TIMERS

//==========================================================================
// Clock functions

//-----------------------------------------------------------------------------
// Set the clocks current time

externC int clock_settime( clockid_t clock_id, const struct timespec *tp)
{
    TIME_ENTRY();

    if( clock_id != CLOCK_REALTIME )
        TIME_RETURN(EINVAL);

    if( !valid_timespec( tp ) )
        TIME_RETURN(EINVAL);
        
    cyg_tick_count ticks = cyg_timespec_to_ticks( tp );

    Cyg_Clock::real_time_clock->set_value( ticks );
    
    TIME_RETURN(0);
}

//-----------------------------------------------------------------------------
// Get the clocks current time

externC int clock_gettime( clockid_t clock_id, struct timespec *tp)
{
    TIME_ENTRY();

    if( clock_id != CLOCK_REALTIME )
        TIME_RETURN(EINVAL);

    if( tp == NULL )
        TIME_RETURN(EINVAL);
    
    cyg_tick_count ticks = Cyg_Clock::real_time_clock->current_value();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -