delayed_preempt.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <stdio.h>
00011 #include <l4/sys/kdebug.h>
00012 #include <l4/util/rdtsc.h>
00013 #include <l4/util/atomic.h>
00014 #include <l4/log/l4log.h>
00015 #include <l4/env/errno.h>
00016 #include <l4/util/macros.h>
00017 #include <l4/thread/thread.h>
00018 #include <l4/cpu_reserve/sched.h>
00019 #include <l4/sys/rt_sched.h>
00020
00021
00022 #define CONFIG_LOG_DP 0
00023
00024
00025 #define CONFIG_LOG_TIMEOUT 1
00026
00027
00028 #define CONFIG_LOG_TO_KERN 1
00029
00030
00031 static int dp_duration;
00032 static volatile l4_int32_t preempt_counter;
00033 static volatile l4_cpu_time_t preempt_start;
00034
00035
00036 static l4thread_t thread=L4THREAD_INVALID_ID;
00037 static void*pc;
00038
00039 int l4cpu_dp_reserve_task(int *duration){
00040 int err;
00041
00042 if(dp_duration || !*duration) return -L4_EINVAL;
00043 if((err = l4cpu_reserve_delayed_preempt(l4_myself(),
00044 0,
00045 0,
00046 duration))!=0){
00047 return err;
00048 }
00049 dp_duration = *duration;
00050 return 0;
00051 }
00052
00053 int l4cpu_dp_active(void){
00054 return preempt_counter;
00055 }
00056
00057 int l4cpu_dp_begin(void){
00058
00059 if(thread == L4THREAD_INVALID_ID){
00060 LOGdk(CONFIG_LOG_DP, "cli()");
00061 l4_rt_dp_begin();
00062 } else {
00063 LOGdk(CONFIG_LOG_DP,"cli'd by %x", thread);
00064 }
00065 if(l4util_inc32_res((l4_uint32_t*)&preempt_counter)==1){
00066 LOGdk(CONFIG_LOG_DP, "delayed_preempt: started");
00067 if(l4cpu_dp_start_callback) l4cpu_dp_start_callback();
00068
00069 preempt_start = l4_tsc_to_us(l4_rdtsc());
00070 thread = l4thread_myself();
00071 pc = __builtin_return_address(0);
00072 return 0;
00073 }
00074
00075
00076
00077 LOGdk(CONFIG_LOG_DP,
00078 "delayed_preempt: ++ctr=%d", preempt_counter);
00079 if(thread == l4thread_myself()) return 0;
00080 else {
00081 char buf[10];
00082 sprintf(buf, "already started by: %x PC=%p", thread, pc);
00083 outstring(buf);
00084 enter_kdebug("preemption started twice");
00085 return -L4_EINVAL;
00086 }
00087 }
00088
00089 int l4cpu_dp_end(void){
00090 int err;
00091
00092 if((err=l4util_dec32_res((l4_uint32_t*)&preempt_counter))==0){
00093 l4_cpu_time_t diff;
00094
00095 LOGdk(CONFIG_LOG_DP, "delayed_preempt: done now");
00096
00097 diff = l4_tsc_to_us(l4_rdtsc()) - preempt_start;
00098 if(l4cpu_dp_stop_callback){
00099 l4cpu_dp_stop_callback(diff, pc);
00100 }
00101
00102 if(diff > dp_duration){
00103 if(CONFIG_LOG_TO_KERN){
00104 LOGdk(CONFIG_LOG_DP, "DP timeout: %uus/%uus.",
00105 (unsigned)diff, dp_duration);
00106 } else {
00107 LOGdl(CONFIG_LOG_DP,
00108 "Preemption lasted too long: %uµs, requested was %uµs.",
00109 (unsigned)diff,
00110 dp_duration);
00111 }
00112 err = -L4_ETIME;
00113 goto e_return;
00114 }
00115 err = dp_duration-diff;
00116 goto e_return;
00117 }
00118 LOGdk(CONFIG_LOG_DP, "delayed_preempt: --ctr=%d", err);
00119 if(err<0){
00120 enter_kdebug("preemption not started");
00121 err = -L4_EINVAL;
00122 goto e_return;
00123 }
00124
00125 return 0;
00126
00127 e_return:
00128 thread = L4THREAD_INVALID_ID;
00129 pc=0;
00130 LOGdk(CONFIG_LOG_DP, "sti()");
00131 l4_rt_dp_end();
00132 return err;
00133 }