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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [compat/] [posix/] [v2_0/] [src/] [time.cxx] - Blame information for rev 579

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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