delayed_preempt.c

Go to the documentation of this file.
00001 /*!
00002  * \file   cpu_reserve/lib/src/delayed_preempt.c
00003  * \brief  Delayed Preemption Emulation
00004  *
00005  * \date   09/22/2004
00006  * \author Jork Loeser <jork.loeser@inf.tu-dresden.de>
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 /*!\brief Log delayed preemption calls */
00022 #define CONFIG_LOG_DP 0
00023 
00024 /*!\brief Log timeouts */
00025 #define CONFIG_LOG_TIMEOUT 1
00026 
00027 /*!\brief Log timeouts to Fiasco tracebuffer (1) or Log (0) */
00028 #define CONFIG_LOG_TO_KERN 1
00029 
00030 
00031 static int dp_duration;                         /* microseconds */
00032 static volatile l4_int32_t preempt_counter;
00033 static volatile l4_cpu_time_t preempt_start;    /* 0 if none started */
00034 
00035 /* for debugging purposes: */
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,  /* id */
00045                                             0,  /* prio */
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     /* We need to cli only if nobody owns the lock. */
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     /* preemption was already started. However, we allow multiple
00076      * starts from the same thread due to the spin_lock implementation */
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     /* still someone in the preemption, just return */
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 }

CPU reservation server Reference Manual, written by Jork Loeser  © 2004