// // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // alarm.c -- // // Author : Thierry Delisle // Created On : Fri Jun 2 11:31:25 2017 // Last Modified By : Peter A. Buhr // Last Modified On : Fri Jul 21 22:35:18 2017 // Update Count : 1 // extern "C" { #include #include #include #include #include #include } #include "alarm.h" #include "kernel_private.h" #include "preemption.h" //============================================================================================= // time type //============================================================================================= #define one_second 1_000_000_000ul #define one_milisecond 1_000_000ul #define one_microsecond 1_000ul #define one_nanosecond 1ul __cfa_time_t zero_time = { 0 }; void ?{}( __cfa_time_t & this ) { this.val = 0; } void ?{}( __cfa_time_t & this, zero_t zero ) { this.val = 0; } void ?{}( itimerval & this, __cfa_time_t * alarm ) with( this ) { it_value.tv_sec = alarm->val / one_second; // seconds it_value.tv_usec = max( (alarm->val % one_second) / one_microsecond, 1000 ); // microseconds it_interval.tv_sec = 0; it_interval.tv_usec = 0; } void ?{}( __cfa_time_t & this, timespec * curr ) { uint64_t secs = curr->tv_sec; uint64_t nsecs = curr->tv_nsec; this.val = (secs * one_second) + nsecs; } __cfa_time_t ?=?( __cfa_time_t & this, zero_t rhs ) { this.val = 0; return this; } __cfa_time_t from_s ( uint64_t val ) { __cfa_time_t ret; ret.val = val * 1_000_000_000ul; return ret; } __cfa_time_t from_ms( uint64_t val ) { __cfa_time_t ret; ret.val = val * 1_000_000ul; return ret; } __cfa_time_t from_us( uint64_t val ) { __cfa_time_t ret; ret.val = val * 1_000ul; return ret; } __cfa_time_t from_ns( uint64_t val ) { __cfa_time_t ret; ret.val = val * 1ul; return ret; } //============================================================================================= // Clock logic //============================================================================================= __cfa_time_t __kernel_get_time() { timespec curr; clock_gettime( CLOCK_REALTIME, &curr ); return (__cfa_time_t){ &curr }; } void __kernel_set_timer( __cfa_time_t alarm ) { itimerval val = { &alarm }; setitimer( ITIMER_REAL, &val, NULL ); } //============================================================================================= // Alarm logic //============================================================================================= void ?{}( alarm_node_t & this, thread_desc * thrd, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time ) with( this ) { this.thrd = thrd; this.alarm = alarm; this.period = period; next = 0; set = false; kernel_alarm = false; } void ?{}( alarm_node_t & this, processor * proc, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time ) with( this ) { this.proc = proc; this.alarm = alarm; this.period = period; next = 0; set = false; kernel_alarm = true; } void ^?{}( alarm_node_t & this ) { if( this.set ) { unregister_self( &this ); } } __cfaabi_dbg_debug_do( bool validate( alarm_list_t * this ) { alarm_node_t ** it = &this->head; while( (*it) ) { it = &(*it)->next; } return it == this->tail; }) static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) { verify( !n->next ); if( p == this->tail ) { this->tail = &n->next; } else { n->next = *p; } *p = n; verify( validate( this ) ); } void insert( alarm_list_t * this, alarm_node_t * n ) { alarm_node_t ** it = &this->head; while( (*it) && (n->alarm > (*it)->alarm) ) { it = &(*it)->next; } insert_at( this, n, it ); verify( validate( this ) ); } alarm_node_t * pop( alarm_list_t * this ) { alarm_node_t * head = this->head; if( head ) { this->head = head->next; if( !head->next ) { this->tail = &this->head; } head->next = NULL; } verify( validate( this ) ); return head; } static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) { verify( it ); verify( (*it) == n ); (*it) = n->next; if( !n-> next ) { this->tail = it; } n->next = NULL; verify( validate( this ) ); } static inline void remove( alarm_list_t * this, alarm_node_t * n ) { alarm_node_t ** it = &this->head; while( (*it) && (*it) != n ) { it = &(*it)->next; } verify( validate( this ) ); if( *it ) { remove_at( this, n, it ); } verify( validate( this ) ); } void register_self( alarm_node_t * this ) { alarm_list_t * alarms = &event_kernel->alarms; disable_interrupts(); lock( event_kernel->lock __cfaabi_dbg_ctx2 ); { verify( validate( alarms ) ); bool first = !alarms->head; insert( alarms, this ); if( first ) { __kernel_set_timer( alarms->head->alarm - __kernel_get_time() ); } } unlock( event_kernel->lock ); this->set = true; enable_interrupts( __cfaabi_dbg_ctx ); } void unregister_self( alarm_node_t * this ) { disable_interrupts(); lock( event_kernel->lock __cfaabi_dbg_ctx2 ); { verify( validate( &event_kernel->alarms ) ); remove( &event_kernel->alarms, this ); } unlock( event_kernel->lock ); enable_interrupts( __cfaabi_dbg_ctx ); this->set = false; } // Local Variables: // // mode: c // // tab-width: 4 // // End: //