// // 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 May 25 06:25:47 2018 // Update Count : 67 // extern "C" { #include #include #include #include #include } #include "alarm.h" #include "kernel_private.h" #include "preemption.h" //============================================================================================= // Clock logic //============================================================================================= Time __kernel_get_time() { timespec curr; clock_gettime( CLOCK_MONOTONIC_RAW, &curr ); // CLOCK_REALTIME return (Time){ curr }; } void __kernel_set_timer( Duration alarm ) { verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm.tv); setitimer( ITIMER_REAL, &(itimerval){ alarm }, NULL ); } //============================================================================================= // Alarm logic //============================================================================================= void ?{}( alarm_node_t & this, thread_desc * thrd, Time alarm, Duration period ) 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, Time alarm, Duration period ) 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 ); } } #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__)) bool validate( alarm_list_t * this ) { alarm_node_t ** it = &this->head; while( (*it) ) { it = &(*it)->next; } return it == this->tail; } #endif 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: //