Páginas

domingo, 26 de febrero de 2012

PyMite from Interruption Space

Se que ultimamente estoy hablando mucho de PyMite en lugar de sobre Gaia, mi verdadero proyecto para el concurso de este año, pero puesto que en cierto modo se me quedo la espinita clavada por la tonteria del bug por usar una version de Python demasiada moderna, lo cierto es que lo he estado usando como campo de pruebas para despues aplicar las mejoras a Gaia directamente. Sin embargo, esta vez mi trabajo en PyMite se merece un post por derecho propio:

PyMite capturando los scancodes del teclado mediante eventos. Si niños: he conseguido capturar y procesar interrupciones directamente desde dentro de Python :-D

¿Que como lo he hecho? Bien, vayamos por partes:

  • En primer lugar, hace falta tener funcionando un gestor de interrupciones en C. Esto no es demasiado problema, puesto que tambien es necesario para poder capturar las interrupciones del reloj del sistema (que eso ya lo habia conseguido) y para poder capturar las interrupciones del teclado para poder usarlo como entrada estandar, asi que eso ya estaba listo. Trivial, vamos.
  • Una vez hecho eso, el siguiente es añadir handlers para las interrupciones que queremos manejar (en principio todas). Para ello, me he hecho una funcion init() nativa dentro de events.py (un nuevo modulo que he hecho para gestionar los eventos, luego hablo mas de ello) que se encarga de inicializar la cola de eventos, de registrar el handler para las interrupciones en los que estamos interesados para que las guarde en la cola de eventos, y tambien de guardar un puntero a la funcion que se va a encargar despues de extraer los eventos y procesarlos, esta vez ya en Python. Todo el codigo esta sacado de Gaia con pequeñas modificaciones ya que la filosofia de diseño de hacerlo puramente orientado a eventos es comun para los dos, asi que he decidido reutilizar la idea de usar una unica cola global de eventos y que despues se vayan "bombeando" y procesando secuencialmente uno detras de otro como pequeñas unidades de codigo atomicas e independientes, muy inspirado en como funcionan Node.js o el motor de eventos Twisted (del cual soy un fan declarado... :-D ).
  • Una vez que se produce una interrupcion, se lanza el handler que hemos definido para manejarlos (tambien nativo) el cual simplemente añade un nuevo evento a la cola de eventos, llama al bombeador de eventos y sale de la interrupcion (esta fue sencilla... ;-) ).
  • Finalmente, el bombeador de eventos se asegura de que nadie mas los esta procesando (principalmente porque se haya producido una interrupcion mientras todavia no se habian terminado de procesar los pendientes) y en tal caso, va vaciando la cola de eventos y procesandolos uno a uno ejecutando las funciones que se hubiesen registrado para cada uno de ellos. Al tener que acceder a la cola de eventos y estar esta declarada en C estoy usando un par de funciones nativas para comprobar si esta vacia y para extraer uno de los eventos, nada mas.
Simple, facil y para toda la familia :-D Y por supuesto, todo subido al repositorio... :-)

Sin embargo hay truco: por un lado, no estoy generando eventos en Python propiamente dichos, sino que solo estoy guardando el nombre del evento. Esto es asi para que el handler fuera mas pequeño al posponer la conversion a objetos Python y volviera antes de la interrupcion, pero sin lugar a dudas si quiero usar una cola de eventos unica tendre que cambiarlo. Otra opcion seria el tratar las interrupciones en dos pasos, con una cola de interrupciones y despues convertirlas y añadirlas a la cola de eventos en un paso posterior. Esto aislaria por completo el procesamiento de interrupciones de el de eventos con lo que quedaria muchisimo mas limpio, pero tambien añadiria mas retrasos... habra que estudiarlo. Otro truco que usa que me ha sugerido el propio autor de PyMite (aunque al final no lo estoy haciendo como el me ha propuesto) y que es mas interesante, es que al tener PyMite su propio gestor de hilos y ademas puede cambiar automaticamente de uno a otro si ha estado uno de ellos mucho tiempo en la CPU (¿hilos preemptivos? eso en mi barrio se le llama procesos... :-P ) lo estoy aprovechando y en lugar de procesar los eventos directamente (con lo que el "proceso" que estaba en ejecucion cuando se produjo la interrupcion se queda esperando) los estoy lanzando en un nuevo hilo para que se procesen de forma autonoma mas adelante y asi poder volver inmediatamente de la interrupcion :-)


Por otra parte, hay espacio para limpiar codigo y para optimizar para aburrir. En primer lugar, actualmente no es threadsafe puesto que no estoy usando ninguna estructura que lo haga. En Gaia el bombeo de eventos esta protegido con un lock, pero al necesitar guardar la funcion a usar para el bombeo desconozco si podria usar una funcion nativa (supongo que si), por lo que estoy usando un simple booleano (¡¡¡error!!! :-S ), asi que eso tengo que arreglarlo pronto. Tambien estaria la posibilidad de usar la clase Queue de Python, pero tiene muchas dependencias que la libreria estandar de PyMite no me satisface, asi que por el momento descartado. Por ultimo, claro esta, lo que he comentado anteriormente de separar la cola de interrupciones de la de eventos, pero esa es otra historia... :-D En resumen, que en unos commits estara listo ;-)

Y eso es todo por ahora, me falta explicar como se usan dichas interrupciones desde Python pero eso lo explicare en otro post (aunque lo cierto es que ahora deberia centrarme en estudiar para los examenes... :-/ ). Lo que si me he dado cuenta es que el problema de la limitacion de memoria para el kernel en x86 es real, ya que me ha vuelto a pasar con PyMite aunque increiblemente en PyMite ha tardado mucho mas en aparecer que con Gaia: ha sido eliminar las funciones de acceso a los puertos de entrada/salida que no estaba usando y arreglarse el problema... :-/

P.D.: para los que no lo hayan entendido, el titulo del post es una parodia de Plan 9 from User Space, el port para Unix/Linux de las librerias del sistema operativo Plan 9, con el cual tengo una relacción de amor-odio digna de poner en el Facebook como "es complicado"... :-P

martes, 21 de febrero de 2012

It works!


PyMite corriendo sobre QEmu (x86) usando por debajo el codigo de Gaia mostrando un timer basado en interrupciones :-D

lunes, 20 de febrero de 2012

PyMite

Originariamente no iba a desarrollar Gaia, todo fue fruto de las circunstancias. Desde siempre tuve claro que mi sistema operativo tendria una arquitectura microkernel, sin embargo tambien queria que fuera seguro y facil de entender, de ahi que la arquitectura exokernel fuera ganando fuerza: el menor codigo posible corriendo como supervisor, y todo lo demas corriendo como espacio de usuario. Esto se podria potenciar mas si no solo se usan dos ejecutables distintos (Gaia y Uranus) sino que directamente estaban escritos en dos lenguajes distintos, y que dos mejores opciones que mis grandes amores C++ y Python :-D

Proyectos para hacer un sistema operativo en Python ha habido algunos, pero no han llegado a buen termino, en parte por la mala fama que tiene Python de ser lento (lo cual no es "tan" cierto...). Sin embargo poco antes de comenzar la edicion del concurso de este año descubri la existencia de PyMite, y en ese momento vi claro que es lo que debia hacer :-D

PyMite aka Python-on-a-chip es una maquina virtual Python diseñada para correr sobre microcontroladores de 8 bits... y sin sistema operativo por debajo, directamente sobre el metal :-) Ironicamente, aunque existe la posibilidad de compilarlo para escritorio para pruebas no habia ninguna plataforma echa para que corriera sobre PCs estandar directamente, luego ¿que mejor manera de colaborar con el software libre? Y ademas, me conseguia una base solida sobre la que programar mi sistema operativo comodamente sin tener que diseñarme mis propias estructuras de datos: dos por el precio de uno :-)

Asi que me puse a ello, mirando documentacion y haciendo pruebas. Lo tenia todo listo, y a la hora de ejecutar... fallo. Un bug tan raro que ni el programador original pudo decirme que podria pasar :-( Habia perdido un tiempo precioso y ademas ya estaba mentalizado en desarrollar de una vez por todas mi propio sistema operativo, por lo que decidi cambiar mi proyecto de portar PyMite a la arquitectura x86 a desarrollar mi propio exokernel que sustituyera la labor que realizaria PyMite de abstraer a bajo nivel el hardware, y asi surgio Gaia, la madre tierra.

Sin embargo, la semana pasada recibi un e-mail sobre no-se-que indicandome que podria ser mi version de Python ya que al ser muy reciente generaba bytecodes que eran interpretados como basura. Al principio no sabia a que se referia hasta que vi de donde procedia: ¡era el bug que notifique hacia 5 meses! La verdad que no confiaba mucho en una idea feliz tan absurda, aunque tenia sentido asi que decidi probarla: me baje mi viejo codigo, compile el entorno usando Python 2.6 en lugar del 2.7.2 que viene por defecto, ejecuto... y no me lo podia creer, la excepcion habia desaparecido. ¡El ultimo paso que me faltaba, al final lo tenia! :-D Tarde, pero al menos ya no me quedaba con el regusto de no haberlo conseguido: PyMite estaba corriendo sobre una nueva plataforma y todo gracias a mi... y al mensaje de un desconocido :-D

Asi que estos dias le he estado dando un pequeño empujon canibalizando el codigo de Gaia (al igual que hace 5 meses hice en sentido inverso) y lo cierto es que me estoy llevando una grata noticia: no solo me esta siendo mucho mas facil entender como hacer las cosas al haberme peleado antese-mail con Gaia (y ademas ya funciona el timer con PyMite :-P ) sino que ademas, ¡casi no estoy picando codigo! ¡¡Todo es copy & paste!! :-D Luego en cierto sentido creo que "parte" de mi proposito al desarrollar Gaia se esta cumpliendo: un framework para hacer facil el desarrollo de sistemas operativos sin tener que preocuparse de las menudeces porque ya estan hechas :-) Por el momento el copy&paste es descarado porque al pillarme la noticia un poco por sorpresa actualmente Gaia de framework tiene poco... pero si que el codigo esta bastante claro con lo que no me esta costando nada adaptarlo :-)

Lo bueno de esto es que me va a servir para tener otro entorno de pruebas aparte de ChaOS para aumentar la portabilidad y abstraccion de Gaia, lo cual es bueno, y ademas tambien me permite colaborar con un proyecto de software libre bastante grande, lo cual esta genial :-D De momento estoy pensando en separar la libreria del sistema a un proyecto aparte (GaiaLib), con vistas a en el futuro sustituirla por NewLib (aunque lo cierto es que no me esta quedando nada mal... :-D ), y quien sabe si no podre sacar mas codigo reutilizable. Al final con la tonteria, lo que iba a ser un simple proyecto para el concurso ya van colaboraciones en cuatro distintos... :-P

sábado, 11 de febrero de 2012

Featuring Norm

Como os dije en mi anterior entrada, debido al estres y desesperación que me estaba ocasionando el que Gaia cascara por cualquier tonteria decidi darme un respiro y mejorar en mi sistema de archivos, y una de esas mejoras fue justamente quitar todas las referencias a SQLite de la capa de abstracción a la base de datos y limpiarla un poquito. ¿Que pasa? Que como tiene la caracteristica de que es bastante generica al tener todas las consultas SQL en archivos externos, entonces ya no hay ninguna referencia al sistema de archivos y se podria aislar como un paquete independiente para poder usarlo en otros proyectos. Pues bien: un poco de magia con la ayuda de GitHub, un poquito de limpieza de codigo para que quede mas presentables y unas cuantas optimizaciones (las cuales incluso han hecho que PirannaFS sea mas limpio y rapido :-) ) y asi es como nacio Norm.

Tradicionalmente, los ORM se han usado para definir a alto nivel los datos, de forma que fuera facil de usar para el programador, pero de esta forma se pierde el control de como se estan guardando (lo cual no es malo, es la mayoria de los casos no es del todo importante), y ademas al hacerlo de una forma generica ralentizando el acceso y termina siendo un cuello de botella y creando problemas en aplicaciones que necesitan un gran rendimiento.

Sin embargo, Norm funciona al reves: en lugar de centrarse en la aplicacion y generar internamente el codigo SQL necesario para acceder a los datos, se centra justamente en estos y en como se accede a ellos en la base de datos y genera el codigo necesario para poder usarlos desde la aplicacion. De esta forma, se puede diseñar a mano codigo SQL optimizado para la aplicacion en concreto teniendo un control total sobre los datos sin tener que escribir todo el glue code necesario para poder usarlo ya que de esto ya se encarga Norm, y ademas genera una API especifica para la aplicacion muy sencilla de usar. Si a esto le añadimos que ademas el codigo SQL no esta embebido dentro del codigo del programa principal como se ha hecho hasta ahora cuando se necesitaba este tipo de optimizaciones sino que se guarda en archivos independientes faciles de mantener y de actualizar sin tocar el codigo del programa principal, no me extraña que al final de la presentacion que hice ayer en las oficinas de Tuenti para Python-Madrid la gente mostrara tanto interes e incluso me diesen ideas para mejorarlo o quisieran colaborar en su desarrollo... :-)


¿Sera posible que por primera vez haya hecho algo que realmente sea util para la gente? ¿Al final sera capaz PirannaFS de sacarme de pobre? :-P

domingo, 5 de febrero de 2012

Gaia is back

Bien es cierto que no escribo mucho por aca, pero lo cierto es que no soy muy dado a escribir... :-P Pero bueno, como considero que debo manteneros informados de mis avances, alla voy :-D

Lo cierto es que muchos avances no ha habido con Gaia a pesar de el tiempo dedicado, la paginacion me ha estado dando muchos problemas y a ser sinceros, me ha deprimido. He intentado solucionarlo usando el codigo original de James Mallory (de cuyos tutoriales sobre sistemas operativos he estado usando como referencia) para ir adaptandolo a mi arquitectura y ver en donde estaba fallando, pero lo cierto es que ya me aburri (que es lo peor que le puede pasar a alguien que desarrolla software libre, que deje de divertirse con lo que hace) y deje el proyecto aparcado/abandonado hasta que viera un poco de luz. Es por eso por lo que si veis mi perfil en Github vereis que le he estado dando un buen empujon a PirannaFS en las ultimas semanas: por alguna razon, me sigue motivando e inspirando :-)

Sin embargo... esa luz llego, aunque fuese solo con forma de cerilla: a traves de la wikipedia llegue por casualidad al sistema operativo Gavin, y justo en uno de los commits indicaba que estaba usando -O2 al compilar para optimizar el codigo porque añadia una variable y dejaba de arrancar (uno de los problemas que me sucedian a mi) ya que al parecer, al arrancar se dispone de muy poco espacio en memoria para el kernel. Añadir el flag, compilar... y adios problema :-D Asi que aprovechando la buena nueva decidi darle un empujon al gestor de interrupciones y limpiar un poco la arquitectura antes de continuar con la paginacion. Gracias a esto puedo decir: si, mi arquitectura funciona, y es correcta, se puede hacer un sistema operativo puramente orientado a eventos :-D Ahora el problema esta en que por alguna razon los syscalls ya no funcionan correctamente, con lo que no puedo leer del teclado :-( Bien es cierto que una de las razones por las que empece Gaia era precisamente para evitar a la gente en el futuro que se rompiera la cabeza como me la estoy rompiendo yo ahora, pero tampoco me imagine que x86 fuese una plataforma tan mala para trabajar a bajo nivel... :-(

En fin, permanezcan en antena, a ver si hacemos algo de provecho en las proximas semanas...