// -*- Mode: CFA -*- // // 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 : Thierry Delisle // Last Modified On : -- // Update Count : 0 // extern "C" { #include #include } #include "alarm.h" #include "kernel_private.h" #include "preemption.h" //============================================================================================= // Clock logic //============================================================================================= __cfa_time_t __kernel_get_time() { timespec curr; clock_gettime( CLOCK_REALTIME, &curr ); return ((__cfa_time_t)curr.tv_sec * TIMEGRAN) + curr.tv_nsec; } void __kernel_set_timer( __cfa_time_t alarm ) { itimerval val; val.it_value.tv_sec = alarm / TIMEGRAN; // seconds val.it_value.tv_usec = (alarm % TIMEGRAN) / ( TIMEGRAN / 1_000_000L ); // microseconds val.it_interval.tv_sec = 0; val.it_interval.tv_usec = 0; setitimer( ITIMER_REAL, &val, NULL ); } //============================================================================================= // Alarm logic //============================================================================================= void ?{}( alarm_node_t * this, thread_desc * thrd, __cfa_time_t alarm = 0, __cfa_time_t period = 0 ) { this->thrd = thrd; this->alarm = alarm; this->period = period; this->next = 0; this->set = false; this->kernel_alarm = false; } void ?{}( alarm_node_t * this, processor * proc, __cfa_time_t alarm = 0, __cfa_time_t period = 0 ) { this->proc = proc; this->alarm = alarm; this->period = period; this->next = 0; this->set = false; this->kernel_alarm = true; } void ^?{}( alarm_node_t * this ) { if( this->set ) { unregister_self( this ); } } static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) { assert( !n->next ); if( p == this->tail ) { this->tail = &n->next; } else { n->next = *p; } *p = n; } 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 ); } 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; } return head; } static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) { verify( it ); verify( (*it)->next == n ); (*it)->next = n->next; if( !n-> next ) { this->tail = it; } n->next = NULL; } static inline void remove( alarm_list_t * this, alarm_node_t * n ) { alarm_node_t ** it = &this->head; while( (*it) && (*it)->next != n ) { it = &(*it)->next; } if( *it ) { remove_at( this, n, it ); } } void register_self( alarm_node_t * this ) { disable_interrupts(); assert( !systemProcessor->pending_alarm ); lock( &systemProcessor->alarm_lock ); { insert( &systemProcessor->alarms, this ); if( systemProcessor->pending_alarm ) { tick_preemption(); } } unlock( &systemProcessor->alarm_lock ); this->set = true; enable_interrupts(); } void unregister_self( alarm_node_t * this ) { disable_interrupts(); lock( &systemProcessor->alarm_lock ); remove( &systemProcessor->alarms, this ); unlock( &systemProcessor->alarm_lock ); disable_interrupts(); this->set = false; }