// // 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 : Wed Jun 17 16:11:35 2020 // Update Count : 75 // #define __cforall_thread__ #include #include #include #include #include #include "alarm.hfa" #include "kernel/fwd.hfa" #include "preemption.hfa" //============================================================================================= // 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`ns); setitimer( ITIMER_REAL, &(itimerval){ alarm }, 0p ); } //============================================================================================= // Alarm logic //============================================================================================= void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period) with( this ) { this.thrd = thrd; this.alarm = alarm; this.period = period; set = false; type = User; } void ?{}( alarm_node_t & this, processor * proc, Time alarm, Duration period ) with( this ) { this.proc = proc; this.alarm = alarm; this.period = period; set = false; type = Kernel; } void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period ) with( this ) { this.alarm = alarm; this.period = period; this.callback = callback; set = false; type = Callback; } void ^?{}( alarm_node_t & this ) { if( this.set ) { unregister_self( &this ); } } void insert( alarm_list_t * this, alarm_node_t * n ) { alarm_node_t * it = & (*this)`first; while( it && (n->alarm > it->alarm) ) { it = & (*it)`next; } if ( it ) { insert_before( *it, *n ); } else { insert_last(*this, *n); } verify( validate( *this ) ); } alarm_node_t * pop( alarm_list_t * this ) { verify( validate( *this ) ); alarm_node_t * head = & (*this)`first; if( head ) { remove(*head); } verify( validate( *this ) ); return head; } 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`first; insert( &alarms, this ); if( first ) { __kernel_set_timer( alarms`first.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( *this ); } unlock( event_kernel->lock ); enable_interrupts( __cfaabi_dbg_ctx ); this->set = false; } //============================================================================================= // Utilities //============================================================================================= void sleep( Duration duration ) { alarm_node_t node = { active_thread(), __kernel_get_time() + duration, 0`s }; register_self( &node ); park(); /* paranoid */ verify( !node.set ); /* paranoid */ verify( & node`next == 0p ); /* paranoid */ verify( & node`prev == 0p ); } // Local Variables: // // mode: c // // tab-width: 4 // // End: //