00001 /* spinlock.c */ 00002 00003 #include "routix/system.h" 00004 #include "routix/atomic.h" 00005 #include "routix/debug.h" 00006 00007 // Funciones que aseguran la atomicidad de operaciones basicas 00008 00009 inline int atomic_inc (int *p) 00010 { 00011 cli(); 00012 (*p)++; 00013 sti(); 00014 return *p; 00015 } 00016 00017 inline int atomic_dec (int *p) 00018 { 00019 cli(); 00020 (*p)--; 00021 sti(); 00022 return *p; 00023 } 00024 00025 inline int atomic_asign (int *p, int x) 00026 { 00027 cli(); 00028 *p = x; 00029 sti(); 00030 return *p; 00031 } 00032 00033 inline int atomic_add (int *p, int x) 00034 { 00035 cli(); 00036 *p += x; 00037 sti(); 00038 return *p; 00039 } 00040 00041 inline int atomic_sub (int *p, int x) 00042 { 00043 cli(); 00044 *p -= x; 00045 sti(); 00046 return *p; 00047 } 00048 00049 // Retorna el valor que posee la variable candado, y luego la setea a 1 00050 inline int TestAndSet(spinlock_t *candado) 00051 { 00052 int retorno; 00053 00054 __asm__ __volatile__ ("pushf\n\t" 00055 "cli\n\t" 00056 "movl %2, %0\n\t" 00057 "movl $1, %1\n\t" 00058 "popf" 00059 : "=m" (retorno), "=m" (*candado) 00060 : "r" (*candado)); 00061 00062 /* cli(); 00063 00064 __asm__ __volatile__ ("movl %0, %%ebx ; movl $1, %%eax ; xchg %%eax, (%%ebx)" : : "m" (candado) : "ebx"); 00065 sti(); 00066 */ 00067 return retorno; 00068 } 00069 00070 /* Momentaneamente solo usadas por funciones de kernel */ 00071 00072 // Candado, utilizado para verificar si algun proceso está evaluando el contenido de "valor" 00073 spinlock_t kernel_lock = 0; 00074 00075 00076 //Funcion de bloqueo del semaforo (equivalente a down o wait) 00077 void spin_lock (spinlock_t *valor) 00078 { 00079 while(1) { 00080 // Esperar mientras algún proceso este dentro de spin_lock/spin_unlock 00081 while (TestAndSet(&kernel_lock)); 00082 00083 if (*valor > 0) { 00084 (*valor)--; 00085 break; 00086 } 00087 kernel_lock = 0; 00088 } 00089 kernel_lock = 0; 00090 } 00091 00092 00093 //Funcion de desbloqueo del semaforo (equivalente a up o signal) 00094 void spin_unlock (spinlock_t *valor) 00095 { 00096 // Esperar mientras algún proceso este dentro de spin_lock/spin_unlock 00097 while (TestAndSet(&kernel_lock)); 00098 (*valor)++; 00099 kernel_lock = 0; 00100 } 00101 00102