OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [compat/] [posix/] [current/] [src/] [time.cxx] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      time.cxx
4
//
5
//      POSIX time functions implementation
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12
//
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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):           nickg
43
// Contributors:        nickg
44
// Date:                2000-03-27
45
// Purpose:             POSIX time functions implementation
46
// Description:         This file contains the implementation of the POSIX time
47
//                      functions.
48
//              
49
//              
50
//
51
//####DESCRIPTIONEND####
52
//
53
//==========================================================================
54
 
55
#include <pkgconf/posix.h>
56
 
57
#include <pkgconf/hal.h>
58
#include <pkgconf/kernel.h>
59
 
60
#include <cyg/kernel/ktypes.h>          // base kernel types
61
#include <cyg/infra/cyg_trac.h>         // tracing macros
62
#include <cyg/infra/cyg_ass.h>          // assertion macros
63
 
64
#include "pprivate.h"                   // POSIX private header
65
 
66
#include <time.h>                       // our header
67
#include <sys/time.h>
68
 
69
#include <cyg/kernel/thread.hxx>
70
#include <cyg/kernel/clock.hxx>
71
#include <cyg/kernel/kapi.h>
72
 
73
#include <cyg/kernel/thread.inl>
74
#include <cyg/kernel/clock.inl>
75
 
76
// -------------------------------------------------------------------------
77
// Internal definitions
78
 
79
// Handle entry to a pthread package function. 
80
#define TIME_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );
81
 
82
// Do a time package defined return. This requires the error code
83
// to be placed in errno, and if it is non-zero, -1 returned as the
84
// result of the function. This also gives us a place to put any
85
// generic tidyup handling needed for things like signal delivery and
86
// cancellation.
87
#define TIME_RETURN(err)                        \
88
CYG_MACRO_START                                 \
89
    int __retval = 0;                           \
90
    if( err != 0 ) __retval = -1, errno = err;  \
91
    CYG_REPORT_RETVAL( __retval );              \
92
    return __retval;                            \
93
CYG_MACRO_END
94
 
95
//==========================================================================
96
// Timer control structures
97
 
98
#ifdef CYGPKG_POSIX_TIMERS
99
typedef struct
100
{
101
    timer_t             id;             // id value for checking
102
    Cyg_Alarm           *alarm;         // eCos alarm object
103
    cyg_bool            armed;          // is alarm enabled?
104
    cyg_bool            pending;        // is expiry pending?
105
    int                 overrun;        // Overrun count
106
    struct sigevent     sigev;          // Sigevent to raise on expiry
107
 
108
    // Space for alarm object
109
    cyg_uint8           alarm_obj[sizeof(Cyg_Alarm)];
110
 
111
} posix_timer;
112
 
113
// Mutex for controlling access to shared data structures
114
static Cyg_Mutex timer_mutex CYGBLD_POSIX_INIT;
115
 
116
// Array of timer objects
117
static posix_timer timer_table[_POSIX_TIMER_MAX];
118
 
119
// Index of next timer to allocate from array
120
static int timer_next = 0;
121
 
122
// This is used to make timer_t values unique even when reusing
123
// a table slot. This allows _POSIX_TIMER_MAX to range
124
// up to 1024.
125
#define TIMER_ID_COOKIE_INC 0x00000400
126
#define TIMER_ID_COOKIE_MASK (TIMER_ID_COOKIE_INC-1)
127
static timer_t timer_id_cookie = TIMER_ID_COOKIE_INC;
128
 
129
#endif // ifdef CYGPKG_POSIX_TIMERS
130
 
131
//-----------------------------------------------------------------------------
132
// new operator to allow us to invoke the constructor on
133
// posix_timer.alarm_obj.
134
 
135
inline void *operator new(size_t size,  cyg_uint8 *ptr) { return (void *)ptr; };
136
 
137
//==========================================================================
138
// Time conversion variables
139
// These are used to interconvert between ticks and POSIX timespecs.
140
 
141
// Converters from sec and ns to ticks
142
static struct Cyg_Clock::converter ns_converter, sec_converter;
143
 
144
// Converters from ticks to sec and ns
145
static struct Cyg_Clock::converter ns_inverter, sec_inverter;
146
 
147
// tickns is the number of nanoseconds per tick.
148
static cyg_tick_count tickns;
149
 
150
static cyg_bool converters_initialized = false;
151
 
152
//==========================================================================
153
// Local functions
154
 
155
static void init_converters()
156
{
157
    if( !converters_initialized )
158
    {
159
 
160
        // Create the converters we need.
161
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1, &ns_converter );
162
        Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
163
        Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1, &ns_inverter );
164
        Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1000000000, &sec_inverter );
165
 
166
        tickns = Cyg_Clock::convert( 1, &ns_inverter );
167
 
168
        converters_initialized = true;
169
    }
170
}
171
 
172
static cyg_bool valid_timespec( const struct timespec *tp )
173
{
174
    // Fail a NULL pointer
175
    if( tp == NULL ) return false;
176
 
177
    // Fail illegal nanosecond values
178
    if( tp->tv_nsec < 0 || tp->tv_nsec > 1000000000 )
179
        return false;
180
 
181
    return true;
182
}
183
 
184
externC cyg_tick_count cyg_timespec_to_ticks( const struct timespec *tp,
185
                                              cyg_bool roundup)
186
{
187
    init_converters();
188
 
189
    // Short circuit zero timespecs
190
    if( tp->tv_sec == 0 && tp->tv_nsec == 0 )
191
    {
192
        return 0;
193
    }
194
 
195
    // Convert the seconds field to ticks.
196
    cyg_tick_count ticks = Cyg_Clock::convert( tp->tv_sec, &sec_converter );
197
 
198
    if( roundup )
199
    {
200
        // Convert the nanoseconds. We add (tickns-1) to round the value up
201
        // to the next whole tick.
202
 
203
        ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec+tickns-1, &ns_converter );
204
    }
205
    else
206
    {
207
        // Convert the nanoseconds. This will round down to nearest whole tick.
208
        ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec, &ns_converter );
209
    }
210
 
211
    return ticks;
212
}
213
 
214
externC void cyg_ticks_to_timespec( cyg_tick_count ticks, struct timespec *tp )
215
{
216
    init_converters();
217
 
218
    // short circuit zero ticks values
219
    if( ticks == 0 )
220
    {
221
        tp->tv_sec = 0;
222
        tp->tv_nsec = 0;
223
        return;
224
    }
225
 
226
    // Convert everything to nanoseconds with a long long. For 64-bits,
227
    // this is safe for 544 years. We'll think about it more closer to
228
    // the time...
229
 
230
    unsigned long long nsecs = Cyg_Clock::convert( ticks, &ns_inverter );
231
 
232
    tp->tv_sec = (long)(nsecs / 1000000000ll);
233
    tp->tv_nsec = (long)(nsecs % 1000000000ll);
234
 
235
    CYG_POSTCONDITION(valid_timespec(tp), "Failed to make valid timespec!");
236
}
237
 
238
//==========================================================================
239
// Startup routine.
240
 
241
externC void cyg_posix_clock_start()
242
{
243
    init_converters();
244
}
245
 
246
#ifdef CYGPKG_POSIX_TIMERS
247
//==========================================================================
248
// Alarm action routine
249
// This is called each time an alarm set up by a timer expires.
250
 
251
static void alarm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data )
252
{
253
    posix_timer *timer = (posix_timer *)data;
254
 
255
    if( timer->pending )
256
    {
257
        // If the pending flag is already set, count an overrun and
258
        // do not bother to try and deliver the expiry.
259
 
260
        timer->overrun++;
261
    }
262
    else
263
    {
264
        if( timer->sigev.sigev_notify == SIGEV_SIGNAL )
265
        {
266
            // Set the expiry pending and wake a thread to
267
            // deliver the signal.
268
 
269
            timer->pending = true;
270
 
271
            sigset_t mask;
272
            sigemptyset( &mask );
273
            sigaddset( &mask, timer->sigev.sigev_signo );
274
            cyg_posix_signal_sigwait();
275
            cyg_posix_pthread_release_thread( &mask );
276
        }
277
        else if( timer->sigev.sigev_notify == SIGEV_THREAD )
278
        {
279
            // Thread style notification
280
            // FIXME: implement SIGEV_THREAD
281
        }
282
        // else do nothing
283
    }
284
}
285
 
286
//==========================================================================
287
// Timer ASR routine
288
 
289
externC void cyg_posix_timer_asr( pthread_info *self )
290
{
291
 
292
    // Loop over the timers looking for any that have an
293
    // expiry pending and call cyg_sigqueue() for each.
294
 
295
    for( int i = 0; i < _POSIX_TIMER_MAX; i++ )
296
    {
297
        posix_timer *timer = &timer_table[i];
298
 
299
        if( timer->id != 0 && timer->pending )
300
        {
301
            timer->pending = false;
302
 
303
            // Call into signal subsystem...
304
            cyg_sigqueue( &timer->sigev, SI_TIMER );
305
 
306
            timer->overrun = 0;
307
        }
308
    }
309
}
310
 
311
#endif // ifdef CYGPKG_POSIX_TIMERS
312
 
313
//==========================================================================
314
// Clock functions
315
 
316
//-----------------------------------------------------------------------------
317
// Set the clocks current time
318
 
319
externC int clock_settime( clockid_t clock_id, const struct timespec *tp)
320
{
321
    TIME_ENTRY();
322
 
323
    if( clock_id != CLOCK_REALTIME )
324
        TIME_RETURN(EINVAL);
325
 
326
    if( !valid_timespec( tp ) )
327
        TIME_RETURN(EINVAL);
328
 
329
    cyg_tick_count ticks = cyg_timespec_to_ticks( tp );
330
 
331
    Cyg_Clock::real_time_clock->set_value( ticks );
332
 
333
    TIME_RETURN(0);
334
}
335
 
336
//-----------------------------------------------------------------------------
337
// Get the clocks current time
338
 
339
externC int clock_gettime( clockid_t clock_id, struct timespec *tp)
340
{
341
    TIME_ENTRY();
342
 
343
    if( clock_id != CLOCK_REALTIME )
344
        TIME_RETURN(EINVAL);
345
 
346
    if( tp == NULL )
347
        TIME_RETURN(EINVAL);
348
 
349
    cyg_tick_count ticks = Cyg_Clock::real_time_clock->current_value();
350
 
351
    cyg_ticks_to_timespec( ticks, tp );
352
 
353
    TIME_RETURN(0);
354
}
355
 
356
 
357
//-----------------------------------------------------------------------------
358
// Get the clocks resolution
359
 
360
externC int clock_getres( clockid_t clock_id, struct timespec *tp)
361
{
362
    TIME_ENTRY();
363
 
364
    if( clock_id != CLOCK_REALTIME )
365
        TIME_RETURN(EINVAL);
366
 
367
    if( tp == NULL )
368
        TIME_RETURN(EINVAL);
369
 
370
    // Get the resolution of 1 tick
371
    cyg_ticks_to_timespec( 1, tp );
372
 
373
    TIME_RETURN(0);
374
}
375
 
376
 
377
//==========================================================================
378
// Timer functions
379
 
380
#ifdef CYGPKG_POSIX_TIMERS
381
 
382
//-----------------------------------------------------------------------------
383
// Create a timer based on the given clock.
384
 
385
externC int timer_create( clockid_t clock_id,
386
                          struct sigevent *evp,
387
                          timer_t *timer_id)
388
{
389
    TIME_ENTRY();
390
 
391
    if( clock_id != CLOCK_REALTIME )
392
        TIME_RETURN(EINVAL);
393
 
394
    timer_mutex.lock();
395
 
396
    posix_timer *timer;
397
    int next = timer_next;
398
 
399
    // Look for an unused slot in the table
400
    while( timer_table[next].id != 0 )
401
    {
402
        next++;
403
        if( next >= _POSIX_TIMER_MAX )
404
            next = 0;
405
 
406
        if( next == timer_next )
407
        {
408
            timer_mutex.unlock();
409
            TIME_RETURN(EAGAIN);
410
        }
411
    }
412
 
413
    timer = &timer_table[next];
414
 
415
    timer_next = next;
416
 
417
    // Make sure we never allocate a zero timer id.
418
    while( timer->id == 0 )
419
    {
420
        timer_id_cookie += TIMER_ID_COOKIE_INC;
421
        timer->id        = next+timer_id_cookie;
422
    }
423
 
424
    if( evp == NULL )
425
    {
426
        // If no evp is supplied, set up the timer
427
        // to use a default set.
428
        timer->sigev.sigev_notify               = SIGEV_SIGNAL;
429
        timer->sigev.sigev_signo                = SIGALRM;
430
        timer->sigev.sigev_value.sival_int      = timer->id;
431
    }
432
    else timer->sigev = *evp;
433
 
434
    timer->alarm        = new( timer->alarm_obj )
435
                               Cyg_Alarm( Cyg_Clock::real_time_clock,
436
                                          alarm_action,
437
                                          (CYG_ADDRWORD)timer );
438
 
439
    timer->armed        = false;
440
    timer->overrun      = 0;
441
 
442
    *timer_id = timer->id;
443
 
444
    timer_mutex.unlock();
445
 
446
    TIME_RETURN(0);
447
}
448
 
449
//-----------------------------------------------------------------------------
450
// Delete the timer
451
 
452
externC int timer_delete( timer_t timerid )
453
{
454
    int err = EINVAL;
455
    TIME_ENTRY();
456
 
457
    posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
458
 
459
    timer_mutex.lock();
460
 
461
    if( timer->id == timerid )
462
    {
463
        // This is a valid timer, disable the kernel
464
        // alarm and delete it.
465
 
466
        // disable alarm
467
        timer->alarm->disable();
468
 
469
        // destroy it
470
        timer->alarm->~Cyg_Alarm();
471
 
472
        // Mark POSIX timer free
473
        timer->id = 0;
474
 
475
        err = 0;
476
    }
477
 
478
    timer_mutex.unlock();
479
 
480
    TIME_RETURN( err );
481
}
482
 
483
//-----------------------------------------------------------------------------
484
// Set the expiration time of the timer.
485
 
486
externC int timer_settime( timer_t timerid, int flags,
487
                           const struct itimerspec *value,
488
                           struct itimerspec *ovalue )
489
{
490
    int err = EINVAL;
491
    TIME_ENTRY();
492
 
493
    if( value == NULL )
494
        TIME_RETURN(EINVAL);
495
 
496
    // convert trigger and interval values to ticks.
497
    cyg_tick_count trigger = cyg_timespec_to_ticks( &value->it_value, true );
498
    cyg_tick_count interval = cyg_timespec_to_ticks( &value->it_interval, true );
499
 
500
    posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
501
 
502
    timer_mutex.lock();
503
 
504
    if( timer->id == timerid )
505
    {
506
        // disable the timer
507
        timer->alarm->disable();
508
 
509
        if( ovalue != NULL )
510
        {
511
            cyg_tick_count otrigger, ointerval;
512
 
513
            timer->alarm->get_times( &otrigger, &ointerval );
514
 
515
            if( timer->armed )
516
            {
517
                // convert absolute trigger time to interval until next trigger
518
                otrigger -= Cyg_Clock::real_time_clock->current_value();
519
            }
520
            else otrigger = 0;
521
 
522
            // convert ticks to timespecs
523
            cyg_ticks_to_timespec( otrigger, &ovalue->it_value );
524
            cyg_ticks_to_timespec( ointerval, &ovalue->it_interval );
525
        }
526
 
527
        if( trigger == 0 )
528
        {
529
            // Mark timer disarmed
530
            timer->armed = false;
531
        }
532
        else
533
        {
534
            // If the ABSTIME flag is not set, add the current time
535
            if( (flags & TIMER_ABSTIME) == 0 )
536
                trigger += Cyg_Clock::real_time_clock->current_value();
537
 
538
            // Set the alarm running.
539
            timer->alarm->initialize( trigger, interval );
540
 
541
            // Mark timer armed
542
            timer->armed = true;
543
 
544
        }
545
 
546
        err = 0;
547
    }
548
 
549
    timer_mutex.unlock();
550
 
551
    TIME_RETURN(err);
552
}
553
 
554
//-----------------------------------------------------------------------------
555
// Get current timer values
556
 
557
externC int timer_gettime( timer_t timerid, struct itimerspec *value )
558
{
559
    int err = EINVAL;
560
 
561
    TIME_ENTRY();
562
 
563
    if( value == NULL )
564
        TIME_RETURN(EINVAL);
565
 
566
    posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
567
 
568
    timer_mutex.lock();
569
 
570
    if( timer->id == timerid )
571
    {
572
        cyg_tick_count trigger, interval;
573
 
574
        timer->alarm->get_times( &trigger, &interval );
575
 
576
        if( timer->armed )
577
        {
578
            // convert absolute trigger time to interval until next trigger
579
            trigger -= Cyg_Clock::real_time_clock->current_value();
580
        }
581
        else trigger = 0;
582
 
583
        // convert ticks to timespecs
584
        cyg_ticks_to_timespec( trigger, &value->it_value );
585
        cyg_ticks_to_timespec( interval, &value->it_interval );
586
        err = 0;
587
    }
588
 
589
    timer_mutex.unlock();
590
 
591
    TIME_RETURN(err);
592
}
593
 
594
//-----------------------------------------------------------------------------
595
// Get number of missed triggers
596
 
597
externC int timer_getoverrun( timer_t timerid )
598
{
599
    int overrun = 0;
600
 
601
    TIME_ENTRY();
602
 
603
    posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
604
 
605
    timer_mutex.lock();
606
 
607
    if( timer->id == timerid )
608
    {
609
        overrun = timer->overrun;
610
    }
611
 
612
    timer_mutex.unlock();
613
 
614
    CYG_REPORT_RETVAL(overrun);
615
    return overrun;
616
}
617
 
618
#endif // ifdef CYGPKG_POSIX_TIMERS
619
 
620
//==========================================================================
621
// Nanosleep
622
// Sleep for the given time.
623
 
624
externC int nanosleep( const struct timespec *rqtp,
625
                       struct timespec *rmtp)
626
{
627
    cyg_tick_count ticks, now, then;
628
 
629
    TIME_ENTRY();
630
 
631
    // check for cancellation first.
632
    PTHREAD_TESTCANCEL();
633
 
634
    // Fail an invalid timespec
635
    if( !valid_timespec( rqtp ) )
636
        TIME_RETURN(EINVAL);
637
 
638
    // Return immediately for a zero delay.
639
    if( rqtp->tv_sec == 0 && rqtp->tv_nsec == 0 )
640
        TIME_RETURN(0);
641
 
642
    // Convert timespec to ticks
643
    ticks = cyg_timespec_to_ticks( rqtp, true );
644
 
645
    CYG_ASSERT( ticks != 0, "Zero tick count");
646
 
647
    Cyg_Thread *self = Cyg_Thread::self();
648
 
649
    // Do the delay, keeping track of how long we actually slept for.
650
    then = Cyg_Clock::real_time_clock->current_value();
651
 
652
    self->delay( ticks );
653
 
654
    now = Cyg_Clock::real_time_clock->current_value();
655
 
656
 
657
    if( rmtp != NULL && (then+ticks) > now )
658
    {
659
        // We woke up early, return the time left.
660
        // FIXME: strictly we only need to do this if we were woken
661
        //        by a signal.
662
 
663
        // Calculate remaining number of ticks.
664
        ticks -= (now-then);
665
 
666
        cyg_ticks_to_timespec( ticks, rmtp );
667
 
668
        // Check for cancellation and then notify the caller that we
669
        // were interrupted.
670
        PTHREAD_TESTCANCEL();
671
        TIME_RETURN(EINTR);
672
    }
673
 
674
    // check if we were woken up because we were cancelled.
675
    PTHREAD_TESTCANCEL();
676
 
677
    TIME_RETURN(0);
678
}
679
 
680
// -------------------------------------------------------------------------
681
// Wait for a signal, or the given number of seconds
682
 
683
externC unsigned int sleep( unsigned int seconds )
684
{
685
    TIME_ENTRY();
686
 
687
    struct timespec timeout;
688
 
689
    timeout.tv_sec = seconds;
690
    timeout.tv_nsec = 0;
691
 
692
    if( nanosleep( &timeout, &timeout ) != 0 )
693
    {
694
        CYG_REPORT_RETVAL(timeout.tv_sec);
695
        return timeout.tv_sec;
696
    }
697
 
698
    TIME_RETURN(0);
699
}
700
 
701
// -------------------------------------------------------------------------
702
// gettimeofday()
703
// Get the current time in a struct timeval
704
externC int gettimeofday(struct timeval* tv, struct timezone* tz)
705
{
706
    int ticks_per_second = 1000000000/
707
      (CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR);
708
    cyg_tick_count_t cur_time = cyg_current_time();
709
    int tix = cur_time % ticks_per_second;
710
    tv->tv_sec = cur_time / ticks_per_second;
711
    tv->tv_usec = (tix * 1000000)/ticks_per_second;
712
    return 0;
713
}
714
 
715
 
716
// -------------------------------------------------------------------------
717
// EOF time.cxx

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.