1 //==========================================================================
5 // POSIX time functions implementation
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
44 // Contributors: nickg
46 // Purpose: POSIX time functions implementation
47 // Description: This file contains the implementation of the POSIX time
52 //####DESCRIPTIONEND####
54 //==========================================================================
56 #include <pkgconf/posix.h>
58 #include <pkgconf/hal.h>
59 #include <pkgconf/kernel.h>
61 #include <cyg/kernel/ktypes.h> // base kernel types
62 #include <cyg/infra/cyg_trac.h> // tracing macros
63 #include <cyg/infra/cyg_ass.h> // assertion macros
65 #include "pprivate.h" // POSIX private header
67 #include <time.h> // our header
70 #include <cyg/kernel/thread.hxx>
71 #include <cyg/kernel/clock.hxx>
72 #include <cyg/kernel/kapi.h>
74 #include <cyg/kernel/thread.inl>
75 #include <cyg/kernel/clock.inl>
77 // -------------------------------------------------------------------------
78 // Internal definitions
80 // Handle entry to a pthread package function.
81 #define TIME_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );
83 // Do a time package defined return. This requires the error code
84 // to be placed in errno, and if it is non-zero, -1 returned as the
85 // result of the function. This also gives us a place to put any
86 // generic tidyup handling needed for things like signal delivery and
88 #define TIME_RETURN(err) \
91 if( err != 0 ) __retval = -1, errno = err; \
92 CYG_REPORT_RETVAL( __retval ); \
96 //==========================================================================
97 // Timer control structures
99 #ifdef CYGPKG_POSIX_TIMERS
102 timer_t id; // id value for checking
103 Cyg_Alarm *alarm; // eCos alarm object
104 cyg_bool armed; // is alarm enabled?
105 cyg_bool pending; // is expiry pending?
106 int overrun; // Overrun count
107 struct sigevent sigev; // Sigevent to raise on expiry
109 // Space for alarm object
110 cyg_uint8 alarm_obj[sizeof(Cyg_Alarm)];
114 // Mutex for controlling access to shared data structures
115 static Cyg_Mutex timer_mutex CYGBLD_POSIX_INIT;
117 // Array of timer objects
118 static posix_timer timer_table[_POSIX_TIMER_MAX];
120 // Index of next timer to allocate from array
121 static int timer_next = 0;
123 // This is used to make timer_t values unique even when reusing
124 // a table slot. This allows _POSIX_TIMER_MAX to range
126 #define TIMER_ID_COOKIE_INC 0x00000400
127 #define TIMER_ID_COOKIE_MASK (TIMER_ID_COOKIE_INC-1)
128 static timer_t timer_id_cookie = TIMER_ID_COOKIE_INC;
130 #endif // ifdef CYGPKG_POSIX_TIMERS
132 //-----------------------------------------------------------------------------
133 // new operator to allow us to invoke the constructor on
134 // posix_timer.alarm_obj.
136 inline void *operator new(size_t size, cyg_uint8 *ptr) { return (void *)ptr; };
138 //==========================================================================
139 // Time conversion variables
140 // These are used to interconvert between ticks and POSIX timespecs.
142 // Converters from sec and ns to ticks
143 static struct Cyg_Clock::converter ns_converter, sec_converter;
145 // Converters from ticks to sec and ns
146 static struct Cyg_Clock::converter ns_inverter, sec_inverter;
148 // tickns is the number of nanoseconds per tick.
149 static cyg_tick_count tickns;
151 static cyg_bool converters_initialized = false;
153 //==========================================================================
156 static void init_converters()
158 if( !converters_initialized )
161 // Create the converters we need.
162 Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1, &ns_converter );
163 Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
164 Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1, &ns_inverter );
165 Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1000000000, &sec_inverter );
167 tickns = Cyg_Clock::convert( 1, &ns_inverter );
169 converters_initialized = true;
173 static cyg_bool valid_timespec( const struct timespec *tp )
175 // Fail a NULL pointer
176 if( tp == NULL ) return false;
178 // Fail illegal nanosecond values
179 if( tp->tv_nsec < 0 || tp->tv_nsec > 1000000000 )
185 externC cyg_tick_count cyg_timespec_to_ticks( const struct timespec *tp,
190 // Short circuit zero timespecs
191 if( tp->tv_sec == 0 && tp->tv_nsec == 0 )
196 // Convert the seconds field to ticks.
197 cyg_tick_count ticks = Cyg_Clock::convert( tp->tv_sec, &sec_converter );
201 // Convert the nanoseconds. We add (tickns-1) to round the value up
202 // to the next whole tick.
204 ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec+tickns-1, &ns_converter );
208 // Convert the nanoseconds. This will round down to nearest whole tick.
209 ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec, &ns_converter );
215 externC void cyg_ticks_to_timespec( cyg_tick_count ticks, struct timespec *tp )
219 // short circuit zero ticks values
227 // Convert everything to nanoseconds with a long long. For 64-bits,
228 // this is safe for 544 years. We'll think about it more closer to
231 unsigned long long nsecs = Cyg_Clock::convert( ticks, &ns_inverter );
233 tp->tv_sec = (long)(nsecs / 1000000000ll);
234 tp->tv_nsec = (long)(nsecs % 1000000000ll);
236 CYG_POSTCONDITION(valid_timespec(tp), "Failed to make valid timespec!");
239 //==========================================================================
242 externC void cyg_posix_clock_start()
247 #ifdef CYGPKG_POSIX_TIMERS
248 //==========================================================================
249 // Alarm action routine
250 // This is called each time an alarm set up by a timer expires.
252 static void alarm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data )
254 posix_timer *timer = (posix_timer *)data;
258 // If the pending flag is already set, count an overrun and
259 // do not bother to try and deliver the expiry.
265 if( timer->sigev.sigev_notify == SIGEV_SIGNAL )
267 // Set the expiry pending and wake a thread to
268 // deliver the signal.
270 timer->pending = true;
273 sigemptyset( &mask );
274 sigaddset( &mask, timer->sigev.sigev_signo );
275 cyg_posix_signal_sigwait();
276 cyg_posix_pthread_release_thread( &mask );
278 else if( timer->sigev.sigev_notify == SIGEV_THREAD )
280 // Thread style notification
281 // FIXME: implement SIGEV_THREAD
287 //==========================================================================
290 externC void cyg_posix_timer_asr( pthread_info *self )
293 // Loop over the timers looking for any that have an
294 // expiry pending and call cyg_sigqueue() for each.
296 for( int i = 0; i < _POSIX_TIMER_MAX; i++ )
298 posix_timer *timer = &timer_table[i];
300 if( timer->id != 0 && timer->pending )
302 timer->pending = false;
304 // Call into signal subsystem...
305 cyg_sigqueue( &timer->sigev, SI_TIMER );
312 #endif // ifdef CYGPKG_POSIX_TIMERS
314 //==========================================================================
317 //-----------------------------------------------------------------------------
318 // Set the clocks current time
320 externC int clock_settime( clockid_t clock_id, const struct timespec *tp)
324 if( clock_id != CLOCK_REALTIME )
327 if( !valid_timespec( tp ) )
330 cyg_tick_count ticks = cyg_timespec_to_ticks( tp );
332 Cyg_Clock::real_time_clock->set_value( ticks );
337 //-----------------------------------------------------------------------------
338 // Get the clocks current time
340 externC int clock_gettime( clockid_t clock_id, struct timespec *tp)
344 if( clock_id != CLOCK_REALTIME )
350 cyg_tick_count ticks = Cyg_Clock::real_time_clock->current_value();
352 cyg_ticks_to_timespec( ticks, tp );
358 //-----------------------------------------------------------------------------
359 // Get the clocks resolution
361 externC int clock_getres( clockid_t clock_id, struct timespec *tp)
365 if( clock_id != CLOCK_REALTIME )
371 // Get the resolution of 1 tick
372 cyg_ticks_to_timespec( 1, tp );
378 //==========================================================================
381 #ifdef CYGPKG_POSIX_TIMERS
383 //-----------------------------------------------------------------------------
384 // Create a timer based on the given clock.
386 externC int timer_create( clockid_t clock_id,
387 struct sigevent *evp,
392 if( clock_id != CLOCK_REALTIME )
398 int next = timer_next;
400 // Look for an unused slot in the table
401 while( timer_table[next].id != 0 )
404 if( next >= _POSIX_TIMER_MAX )
407 if( next == timer_next )
409 timer_mutex.unlock();
414 timer = &timer_table[next];
418 // Make sure we never allocate a zero timer id.
419 while( timer->id == 0 )
421 timer_id_cookie += TIMER_ID_COOKIE_INC;
422 timer->id = next+timer_id_cookie;
427 // If no evp is supplied, set up the timer
428 // to use a default set.
429 timer->sigev.sigev_notify = SIGEV_SIGNAL;
430 timer->sigev.sigev_signo = SIGALRM;
431 timer->sigev.sigev_value.sival_int = timer->id;
433 else timer->sigev = *evp;
435 timer->alarm = new( timer->alarm_obj )
436 Cyg_Alarm( Cyg_Clock::real_time_clock,
438 (CYG_ADDRWORD)timer );
440 timer->armed = false;
443 *timer_id = timer->id;
445 timer_mutex.unlock();
450 //-----------------------------------------------------------------------------
453 externC int timer_delete( timer_t timerid )
458 posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
462 if( timer->id == timerid )
464 // This is a valid timer, disable the kernel
465 // alarm and delete it.
468 timer->alarm->disable();
471 timer->alarm->~Cyg_Alarm();
473 // Mark POSIX timer free
479 timer_mutex.unlock();
484 //-----------------------------------------------------------------------------
485 // Set the expiration time of the timer.
487 externC int timer_settime( timer_t timerid, int flags,
488 const struct itimerspec *value,
489 struct itimerspec *ovalue )
497 // convert trigger and interval values to ticks.
498 cyg_tick_count trigger = cyg_timespec_to_ticks( &value->it_value, true );
499 cyg_tick_count interval = cyg_timespec_to_ticks( &value->it_interval, true );
501 posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
505 if( timer->id == timerid )
508 timer->alarm->disable();
512 cyg_tick_count otrigger, ointerval;
514 timer->alarm->get_times( &otrigger, &ointerval );
518 // convert absolute trigger time to interval until next trigger
519 otrigger -= Cyg_Clock::real_time_clock->current_value();
523 // convert ticks to timespecs
524 cyg_ticks_to_timespec( otrigger, &ovalue->it_value );
525 cyg_ticks_to_timespec( ointerval, &ovalue->it_interval );
530 // Mark timer disarmed
531 timer->armed = false;
535 // If the ABSTIME flag is not set, add the current time
536 if( (flags & TIMER_ABSTIME) == 0 )
537 trigger += Cyg_Clock::real_time_clock->current_value();
539 // Set the alarm running.
540 timer->alarm->initialize( trigger, interval );
550 timer_mutex.unlock();
555 //-----------------------------------------------------------------------------
556 // Get current timer values
558 externC int timer_gettime( timer_t timerid, struct itimerspec *value )
567 posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
571 if( timer->id == timerid )
573 cyg_tick_count trigger, interval;
575 timer->alarm->get_times( &trigger, &interval );
579 // convert absolute trigger time to interval until next trigger
580 trigger -= Cyg_Clock::real_time_clock->current_value();
584 // convert ticks to timespecs
585 cyg_ticks_to_timespec( trigger, &value->it_value );
586 cyg_ticks_to_timespec( interval, &value->it_interval );
590 timer_mutex.unlock();
595 //-----------------------------------------------------------------------------
596 // Get number of missed triggers
598 externC int timer_getoverrun( timer_t timerid )
604 posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
608 if( timer->id == timerid )
610 overrun = timer->overrun;
613 timer_mutex.unlock();
615 CYG_REPORT_RETVAL(overrun);
619 #endif // ifdef CYGPKG_POSIX_TIMERS
621 //==========================================================================
623 // Sleep for the given time.
625 externC int nanosleep( const struct timespec *rqtp,
626 struct timespec *rmtp)
628 cyg_tick_count ticks, now, then;
632 // check for cancellation first.
633 PTHREAD_TESTCANCEL();
635 // Fail an invalid timespec
636 if( !valid_timespec( rqtp ) )
639 // Return immediately for a zero delay.
640 if( rqtp->tv_sec == 0 && rqtp->tv_nsec == 0 )
643 // Convert timespec to ticks
644 ticks = cyg_timespec_to_ticks( rqtp, true );
646 CYG_ASSERT( ticks != 0, "Zero tick count");
648 Cyg_Thread *self = Cyg_Thread::self();
650 // Do the delay, keeping track of how long we actually slept for.
651 then = Cyg_Clock::real_time_clock->current_value();
653 self->delay( ticks );
655 now = Cyg_Clock::real_time_clock->current_value();
658 if( rmtp != NULL && (then+ticks) > now )
660 // We woke up early, return the time left.
661 // FIXME: strictly we only need to do this if we were woken
664 // Calculate remaining number of ticks.
667 cyg_ticks_to_timespec( ticks, rmtp );
669 // Check for cancellation and then notify the caller that we
671 PTHREAD_TESTCANCEL();
675 // check if we were woken up because we were cancelled.
676 PTHREAD_TESTCANCEL();
681 // -------------------------------------------------------------------------
682 // Wait for a signal, or the given number of seconds
684 externC unsigned int sleep( unsigned int seconds )
688 struct timespec timeout;
690 timeout.tv_sec = seconds;
693 if( nanosleep( &timeout, &timeout ) != 0 )
695 CYG_REPORT_RETVAL(timeout.tv_sec);
696 return timeout.tv_sec;
702 // -------------------------------------------------------------------------
704 // Get the current time in a struct timeval
705 externC int gettimeofday(struct timeval* tv, struct timezone* tz)
707 int ticks_per_second = 1000000000/
708 (CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR);
709 cyg_tick_count_t cur_time = cyg_current_time();
710 int tix = cur_time % ticks_per_second;
711 tv->tv_sec = cur_time / ticks_per_second;
712 tv->tv_usec = (tix * 1000000)/ticks_per_second;
717 // -------------------------------------------------------------------------