timer.c

Go to the documentation of this file.
00001 /* timer.c */
00002 
00003 /* Manejo de la interrupcion de timertick y timers */
00004 
00005 #include <routix/system.h>
00006 #include <routix/8254.h>
00007 #include <routix/8259.h>
00008 #include <routix/debug.h>
00009 #include <routix/task.h>
00010 #include <routix/kalloc.h>
00011 #include <routix/time.h>
00012 #include <routix/sched.h>
00013 #include <routix/atomic.h>
00014 #include <routix/timer.h>
00015 #include <sys/list.h>
00016 
00017 // ojo que los jiffies podrian tener un overflow !
00018 // a los 497 dias de estar corriendo
00019 dword jiffies=0;
00020 
00021 // Puntero al inicio de la lista de timers
00022 volatile timer_t *timer_inicio=NULL;
00023 
00024 // Lista de timers
00025 LIST_NEW(timer_t) timer_list = LIST_INITIALIZER;
00026 
00027 void actualizar_timers(void);
00028 inline static int insert_timer(timer_t *nuevo);
00029 inline static int remove_timer(timer_t *timer);
00030 
00031 
00032 void timertick_handler()
00033 {
00034 
00035  endOfInterrupt();
00036  
00037  // Incrementamos el contador de jiffies
00038  jiffies++;
00039 
00040  // Actualizamos el reloj
00041  if ( ! (jiffies % FINTERRUPCION) ) actualizar_reloj(jiffies);
00042 
00043  // Revisamos los timers
00044  actualizar_timers();
00045 
00046   // Chequeamos si el floppy tiene algo pendiente, en realidad colocarlo
00047  // aca tiene un bajo rendimiento, solo para pruebas
00048  floppy_procesar_buffer();
00049 
00050  // Verificamos si hay actualmente una tarea corriendo antes de modificar
00051  // sus estadisticas
00052  if ( actual ) {
00053                 // Actualizamos la cuenta del proceso actual
00054                 actual->cuenta -= 1;
00055                 actual->tiempo_cpu++;
00056 
00057                 // Si se venció la cuenta, la reestablecemos y pasamos el control al scheduler
00058                 if ( actual->cuenta <= 0 ) {
00059                 // Reiniciamos la cuenta
00060                 actual->cuenta = actual->prioridad;
00061                 scheduler();
00062                 __asm__ ("nop");
00063                 }
00064  }
00065 
00066  // Si no la hubiese, devolvemos el control al scheduler
00067  else {
00068         scheduler();
00069  }
00070 
00071 }
00072 
00073 /*
00074 void actualizar_timers(void)
00075 {
00076   timer_t *tmp;
00077 
00078   // Chequeamos si hay timers activos
00079   if ( timer_inicio == NULL ) {
00080    return;
00081   } 
00082 
00083   for ( tmp=timer_inicio; tmp != NULL; tmp = tmp->proximo ) {
00084 
00085     // Debe estar pendiente (ver timer.h) y haber vencido su cuenta
00086     if ( (tmp->estado==PENDIENTE) && (--(tmp->ticks) <= 0) ) {
00087             
00088       // Ejecutamos la funcion establecida
00089       (*(tmp->func))(tmp);
00090 
00091       // Seteamos su estado como finalizado
00092       tmp->estado=FINALIZADO;
00093     }
00094                  
00095   }
00096  
00097 }
00098 */
00099 
00100 
00101 void actualizar_timers(void)
00102 {
00103   timer_t *tmp;
00104         timer_t *toclean;
00105 
00106         // Recorremos la lista procesando los timers vencidos hasta encontrar uno más grande
00107         for(tmp=HEADER_NEXT(timer_list); tmp ;) {
00108 
00109                 if ( TIMER_TICKS(tmp) > jiffies )
00110                         break;
00111 
00112                 // Llamamos a la función seteada en el timer
00113                 (*(TIMER_FUNCTION(tmp)))(tmp);
00114 
00115                 // Lo elimina de la lista
00116                 LIST_DEL(timer_list,timer_list,tmp);
00117 
00118                 toclean=tmp;
00119 
00120                 // buscamos el nodo siguiente
00121                 tmp=LIST_NEXT(timer_list,tmp);
00122                         
00123                 // y lo eliminamos
00124                 clean_timer(toclean);
00125 
00126         }
00127 
00128 }
00129 
00130 
00131 spinlock_t timer_lock = 1;
00132 
00133 /*
00134 int insertar_timer(timer_t *nuevo)
00135 {
00136   // Deshabilitamos Interrupciones
00137   cli();
00138         
00139   timer_t *tmp;
00140         
00141   if ( nuevo == NULL ) { return 0; }
00142 
00143   // Nos paramos al ppio de la lista
00144   tmp = timer_inicio;
00145 
00146   if ( timer_inicio == NULL ) { timer_inicio = nuevo; }
00147 
00148   else {
00149  
00150     // Buscamos la última tarea
00151     for ( tmp = timer_inicio; tmp->proximo != NULL ; tmp = tmp->proximo );
00152 
00153     // Nos colgamos de ella
00154     tmp->proximo = nuevo;
00155   }
00156 
00157   // La nueva tarea queda apuntando a NULL
00158   nuevo->proximo = NULL;
00159 
00160   // Pendiente de ejecucion
00161   nuevo->estado=PENDIENTE;
00162 
00163   // Habilitamos Interrupciones
00164   sti();
00165 
00166   return 1;
00167 }
00168 */
00169 
00170 
00171 inline static int insert_timer(timer_t *nuevo)
00172 {
00173         // Deshabilitamos Interrupciones
00174         START_ATOMIC_OPERATION;
00175         
00176         timer_t *tmp;
00177         
00178         if ( nuevo == NULL ) { return 0; }
00179 
00180         // Buscamos el primer nodo que posea un tiempo mayor al tiempo del nodo nuevo
00181         // de manera que la lista siempre este ordenada de menor a mayor
00182 
00183         // Si la lista está vacia lo insertamos al ppio
00184         //if ( LIST_EMPTY(timer_list) ) {
00185         //      LIST_ADD(timer_list,timer_list,nuevo);
00186         //}
00187 
00188         // Sino buscamos en el listado de timers
00189         //else {
00190         
00191                 LIST_FOREACH(tmp,timer_list,timer_list) {
00192 
00193                         // Dejamos ">=" como criterio así la búsqueda concluye lo antes posible, ya que no importa
00194                         // si queda al ppio o final de un grupo de nodos con el mismo tiempo.
00195                         if ( TIMER_TICKS(tmp) >= TIMER_TICKS(nuevo) )
00196                                 break;
00197                 }
00198 
00199                 // Si no encontramos ningún nodo con tiempo mayor colocamos nuestro nuevo nodo al final de la lista
00200                 if ( tmp==NULL ) {
00201                         LIST_ADD_TAIL(timer_list,timer_list,nuevo);
00202                 }
00203 
00204                 // lo insertamos antes de nuestro nodo encontrado
00205                 else {
00206                         LIST_INSERT_BEFORE(timer_list,timer_list,tmp,nuevo);
00207                 }
00208 
00209         //}
00210 
00211         // Habilitamos Interrupciones
00212         FINISH_ATOMIC_OPERATION;
00213 
00214         return 1;
00215 }
00216 
00217 /*
00218 int remover_timer(timer_t *timer)
00219 {
00220   cli();
00221 
00222   timer_t *tmp;
00223 
00224   // Es el primer timer ?
00225   if ( timer == timer_inicio ) {
00226     timer_inicio = timer->proximo;
00227     sti();
00228     return 0;
00229   }
00230  
00231   // Buscamos nuestro timer entonces
00232   for ( tmp=timer_inicio; (tmp->proximo != timer) && (tmp != NULL) ; tmp = tmp->proximo ) ;
00233 
00234   // Si no encontramos el timer devolvemos error
00235   if ( tmp == NULL ) {
00236     // Lo tengo que reemplazar por la constante correcta según la definición de errno.h
00237     sti();
00238     return -1;
00239   }
00240 
00241   else {
00242     tmp->proximo = timer->proximo;
00243   }
00244 
00245   // Lo tengo que reemplazar por la constante correcta según la definición de errno.h
00246   sti();
00247   return 0;
00248 
00249 }
00250 
00251 */
00252 
00253 inline static int remove_timer(timer_t *timer)
00254 {
00255         // Deshabilitamos Interrupciones
00256         START_ATOMIC_OPERATION;
00257 
00258   timer_t *tmp;
00259 
00260         // Este bloque de cod es opcional y permite que se realice un chequeo adicional
00261         // a la hora de borrar un timer, verificando que exista en la lista
00262         #ifdef SECURE_TIMER_OPER
00263         // Buscamos si realmente existe el timer, para evitar problemas de inconsistencias
00264         LIST_FOREACH(tmp,timer_list,timer_list) {
00265                 if ( tmp==timer )
00266                         break;
00267         }
00268 
00269         // EL timer no existe en la lista !!
00270         if ( tmp==NULL ) {
00271                 FINISH_ATOMIC_OPERATION;
00272                 return -1;              
00273         }
00274 
00275         #endif
00276 
00277         // Lo eliminamos
00278         LIST_DEL(timer_list,timer_list,timer);
00279 
00280         // Habilitamos Interrupciones
00281         FINISH_ATOMIC_OPERATION;
00282 
00283   return 0;
00284 
00285 }
00286 
00287 
00288 inline timer_t *create_timer(dword ticks, task_struct_t *proceso, void (*func)(struct timer_t *info), void *data)
00289 {
00290   timer_t *timer = (timer_t *) malloc(sizeof(timer_t));
00291 
00292         if ( timer==NULL)
00293                 return NULL;
00294 
00295         TIMER_TICKS(timer)=jiffies+ticks;
00296         TIMER_PROCESS(timer)=proceso;
00297         TIMER_FUNCTION(timer)=func;
00298         TIMER_DATA(timer)=data;
00299 
00300   insert_timer(timer);
00301         
00302   return timer;
00303 }
00304 
00305 inline int clean_timer(timer_t *timer)
00306 {
00307         // Chequeamos primero que recibimos un timer    
00308         if ( timer==NULL )
00309                 return -1;
00310         
00311         // Lo sacamos de la lista de timers
00312         
00313         // Si no lo pudimos remover (no existe por ejemplo) retornamos con error
00314         if ( remove_timer(timer) == -1 )
00315                 return -1;
00316         
00317   // Liberamos la memoria la memoria
00318   free(timer);
00319 
00320   return 1;
00321 }
00322 
00323 
00326 inline void timer_dump(void)
00327 {
00328         timer_t *tmp;
00329 
00330   START_ATOMIC_OPERATION;
00331 
00332   kprintf("Pid\n");
00333         LIST_FOREACH(tmp,timer_list,timer_list) {
00334     kprintf("%d\n", TASK_PID(TIMER_PROCESS(tmp)));
00335         }
00336 
00337         FINISH_ATOMIC_OPERATION;
00338 
00339 }

Generated on Sun May 30 18:38:35 2004 for Routix OS by doxygen 1.3.6