Páginas

sábado, 8 de septiembre de 2012

DataChannel polyfill


Han sido tres semanas de duro trabajo, pero finalmente he terminado una implementacion de DataChannel usando WebSockets :-D

Obviamente, no es P2P porque necesita un servidor funcionando como proxy entre los pares, pero puesto que lo he desarrollado a partir de la especificacion deberia ser compatible con su API cuando haya una implementacion nativa en Chrome o Firefox a final de año, o al menos deberia ser util para empezar a trabajar con una mentalidad distribuida en lugar de basada en servidor (esto es lo que mas me ha costado mientras desarrollaba la implementacion :-P ) y probar nuestras aplicaciones. Usarlos es tan simple como incluir datachannel.js en el codigo HTML (despues de cambiar la URL del servidor puesto que actualmente esta metida a pelo), arrancar el servidor proxy y listo, a partir de aqui es completamente autonomo :-D

El codigo se puede encontrar en https://github.com/piranna/DataChannel-polyfill. Tambien tengo una version modificada del codigo de la demo y del cliente de WebRTC.io que he usado para probarlo (sustituyendo el pequeño chat que tienen hecho basado en servidor a una arquitectura P2P enviando los mensajes a todos los pares conectados) que pueden encontrarse en https://github.com/piranna/webrtc.io-demo/tree/polyfill y https://github.com/piranna/webrtc.io-client/tree/polyfill y tambien he hecho un pull-request para que lo añadan en su rama maestra. Por favor mandadme cualquier comentario, consejo o mejora que le veais al codigo :-)

P.D.: por si alguien anda perdido, WebRTC es la especificacion que esta desarrollando para poder conectar los navegadores web directamente entre ellos sin necesidad de un servidor entre medias, y aunque en las ultimas version de Chrome y de Firefox ya hay soporte para realizar videoconferencia directamente desde el navegador y hay algunas aplicaciones que ya empiezan a usarlo (incluso Skype va a cambiar su protocolo para acogerse al estandar), lo cierto es que el soporte para el envio de datos todavia esta por definir y no hay ningun navegador que lo soporte hasta final de año, por lo que para ir preparandome para entonces y poder ir adaptando el codigo para estar listo he desarrollado esta libreria siguiendo la especificacion para que el codigo sea compatible de cara al futuro.

miércoles, 11 de julio de 2012

Achievement unlocked: Chinese spaghetti code

Dos dias y medio peleandome con la funcion de inicializacion de una tarjeta capturadora profesional cuyo codigo de ejemplo no se ajustaba a las especificaciones de la documentacion del fabricante y que devolvia un codigo de error no documentado y totalmente ilogico y descabellado, y descubrir que el problema estaba en que faltaba copiar una libreria dinamica de la cual no hay constancia en ninguna parte y el framework de la tarjeta no echaba en falta en ningun momento ni lanzaba ningun mensaje de error.

He visto cosas que jamas creeriais, returns incondicionales en mitad de una funcion sin venir a cuento, sistemas criticos sin tests cuya configuracion te obligaba a tocar 5 archivos distintos... pero lo de estos chinos no creo que lo supere nada. Despues de esto creo que ya estoy listo para retirarme al Tibet a dedicarme a la meditacion y encontrar mi yo interior...

domingo, 15 de abril de 2012

A veces veo eventos...

A pesar de los fallos relativos al git-svn y tener que trabajar unicamente con el repositorio de GitHub... no he podido resistirme ni tener las manos quietas y he picado mas codigo :-P ¿Y en que he estado liado estos ultimos dias en lugar de estudiar los examenes? Pues ni mas ni menos que con el task manager :-D

El primer paso fue hacer que se imprieran los ticks fuera del driver del temporizador, ya que ahi no hacian nada util. Ahora se estan enviando por el motor de eventos en distintos periodos de tiempo: milisegundos (para lo que he tenido que aumentar la precision del timer, suerte que solo es una variable :-) ), centesimas, decimas y segundos. Asi aunque quizas lo sobrecargue un poco simplemente tengo que acoplarme a la frecuencia adecuada, en este caso centesimas (lo estandar), aunque podria hacer que el cambio de contexto fuese incluso mas rapido si quisiera.

Despues, empece con la definicion basica de lo que seria un proceso internamente para poder delegarles eventos (registrarse directamente en el gestor de eventos del sistema queda un poco feo y complicado, y mas si de todas formas habra que buscar los callbacks dentro de los procesos). Al principio pense en reutilizar la libreria de threads que he hecho para la asignatura de Fundamentos de Sistemas Distribuidos... hasta que me di cuenta que setjmp() y longjmp() son dependientes de cada sistema o no tengo manera posible de implementarlos por el momento :-/ asi que descarte esa idea y me centre por el momento en como hacer para delegar los eventos a sub-diccionarios, y aqui me encontre con otro problema: ¡un diccionario no es una funcion! Asi que como solucion rapida estoy usando un segundo diccionario a la espera de desarrollar mas como seria el tipo Event.

Por ultimo y no menos importante, en un acto de inspiracion divina (en concreto de Morfeo ;-) ) se me ocurrio que aunque actualmente este todo funcionando en el mismo espacio de usuario, podria trabajar con los eventos de los procesos de forma independiente a traves de funciones estaticas... incluso aunque esten en un mismo archivo, siempre que sea este el que se importe. Esto redunda en codigo repetido, si, pero quizas se pueda arreglar pasando las estructuras por parametros. Lo que si que es interesante es el hecho de que el preprocesador se ejecuta de forma lineal, con lo que abusando de el un poco, he conseguido renombrar las funciones relaccionadas con los eventos en el lado de las aplicaciones igual que en el lado del kernel, con lo que solo hace falta cambiar el include para poder pasar el codigo de un lado a otro :-D Esto ultimo es mas util de lo que parece, ya que aparte de hacer el codigo mas limpio, quizas pueda aplicarlo tambien a las llamadas al sistema, y por tanto, que se puedan mover los drivers del espacio de usuario al espacio de kernel de forma totalmente transparente :-D

Como veis, esta todo bastante "en el aire" a la espera de poder dividir el codigo cuando termine el concurso y poder analizar y hacer pruebas independientes de cada parte, pero lo cierto es que al final me esta quedando un API bastante curiosa y flexible y, sobretodo, puramente orientada a eventos (que es lo que queria... :-D )

Update 23:39:

He intentado demostrar mi teoria respecto a usar la misma firma en los syscalls y ha funcionado, pero no como esperaba... sino mejor: puesto que ahora tengo el codigo mas aislado entre sus partes (y sobretodo a nivel de makefile), a la hora de compilarlo cada parte se compila con sus correspondientes syscall.h y syscall.c sin interferirse, luego no hacen falta hacer trucos de ningun tipo: las firmas de los syscalls son iguales que las de las funciones que representan dentro del kernel de forma nativa :-D Chulo, ¿eh? :-)

jueves, 12 de abril de 2012

(Problemas de) ultima hora

Etapa final del concurso de este año y en plena epoca de examenes (al menos para mi, que todavia estoy en el plan antiguo), la tension se vive en el aire... :-D Y me encuentro con problemas :-(

Anoche le estuve dando un repaso a Gaia haciendo que pueda delegar los eventos a "sub-managers" propios de cada aplicacion (el primer paso para poder aislar las aplicaciones del core y que pueda ser realmente multitarea mientras sigue funcionando por eventos) y lo cierto es que consegui que funcionara... hasta cierto punto. El caso es que el motivo por el cual se estaban imprimiendo por pantalla los caracteres dos veces (un bug realmente feo) es porque de hecho estaba procesando el evento dos veces, una al producirse y otra al bombear la cola. "Bien, un bug menos" direis... pues no: resulta que aunque la arquitectura es correcta y de hecho los eventos generados por las interrupciones se estan procesando correctamente, los eventos "software" (en concreto 'VGA/text/putchar', el encargado de escribir en pantalla) se estan llenando de 'V' al principio y por lo tanto no coinciden con ninguno de los registrados (obvio...). ¿Resultado? No se imprime nada en pantalla. Estupendo... Asi que como no consigo encontrar el error (puede deberse a una condicion de carrera o a una mala implementacion del diccionario, aunque visto que siempre ocurre igual supongo que es esto ultimo) y tampoco hay demasiado tiempo, he preferido que los eventos se lancen directamente sin pasar por la cola a espera de poder aislar libGaia cuando termine el concurso y hacer pruebas en condiciones. Esta es una de las razones por las que me gusta tanto Python, que todas las estructuras basicas vienen de serie y ademas estan muy probadas. La parte buena es que el origen del bug de imprimir dos veces ahora esta completamente identificado... :-D

Sin embargo hay otro problema no menos importante: era muy reticente a usar la forja del concurso para este proyecto (a diferencia del año pasado) puesto que por la complejidad del proyecto podia haber problemas... y los ha habido: puesto que al usar git-svn se me creo una nueva rama 'master', Masterbranch no me estaba recogiendo los cambios, asi que intente unir las dos ramas para que estuvieran sincronizadas... y ahora git-svn no funciona. Por suerte el codigo esta a salvo: en la forja del concurso esta una version con el bug anterior corregido y funcionando de forma estable, y puedo seguir subiendo cosas al repositorio de GitHub, luego no hay problemas en este aspecto. Sin embargo, si durante esta semana hago cambios grandes, o bien arreglo git-svn o bien sera mejor acceder directamente al repositorio principal en GitHub.

lunes, 2 de abril de 2012

Un empujoncito...

Bueno, como ya sabreis, nos encontramos en la recta final del concurso de este año, y aunque ya habia pensado en abandonarlo debido a la de lio que he tenido ultimamente y a que literalmente habia perdido la inspiracion... lo cierto es que soy un testarudo :-P

Asi que ya me veis, puesto que habia que entregar un pequeño informe detallado en el Readme del proyecto y tambien subirlo a la forja del concurso, me puse a revisar el codigo por si encontraba donde estaba el fallo por el cual no leia desde el teclado ni se procesaban correctamente los eventos lanzados por las interrupciones, y de pura casualidad los encontre, o al menos encontre una posible solucion añadiendole un pequeño retraso y cambiando los eventos a minusculas (creo que tiene que ver con la busqueda de entradas dentro del diccionario). Segun un amigo mio lo del retraso es debido a una condicion de carrera, pero lo cierto es que no tengo demasiadas ganas de investigarlo por ahora ya que tengo pensado hacer un rediseño completo del proyecto, principalmente convirtiendo el core en un proyecto independiente (libGaia) gracias al hecho de que en PyMite4Multiboot el codigo es practicamente el mismo, con lo que ademas me sera tambien mucho mas facil testearlo (como ya me paso cuando converti AntiORM en un proyecto independiente de PirannaFS).

En resumen: que ya leo desde el teclado correctamente, y acabo de darme cuenta que tenia muy cerquita y al alcance de la mano el poder tener "algo" que se pareciese minimamente a un sistema operativo multitarea y ademas con un esbozo muy claro de cual seria la API de las aplicaciones, en lugar de ser todo una macedonia de frutas callbacks lanzados por eventos. Vale, de acuerdo: un unico espacio de direcciones, todo hardcodeado, sin memoria dinamica... me referia mas al hecho de que aislando los eventos de las aplicaciones en su propia cola (en lugar de usar la del sistema) y el poder cambiar de "aplicaciones" a partir de las interrupciones del reloj del sistema quedaria mas claro cuales son los conceptos a partir de los que queria basar el proyecto. ¿Deberia haberme centrado mas en el proyecto en lugar de dedicar el tiempo a AntiORM? Probablemente. ¿Y respecto a PyMite4Multiboot? No lo creo, ya que justamente al ser mas facil desarrollar sobre el y permitirme ver las cosas desde otro punto de vista no solo he podido definir mejor como orientar el desarrollo futuro del proyecto (o sea: crear libGaia y modularizarlo) y ademas me ha sido mas facil resolver los fallos que tenia con el teclado. En cualquier caso, como dijo Linus Tordvalds y muy especialmente aplicado al software libre, si no es divertido no merece la pena hacerlo... :-D

Ahora, ¿que me depara el futuro? Bueno, a corto plazo centrarme en los examenes (me esperan dos semanas de aupa...), y despues quizas intente a definir la API de las aplicaciones si me da tiempo a hacerlo antes de que termine el plazo de evaluacion del concurso. Despues sin lugar a dudas aislar libGaia y todos los sub-proyectos que han aparecido a lo largo de este año y englobarlos dentro de ChaOS Project, el sistema operativo que llevo queriendo hacer desde que tenia 10 años y lo que realmente hizo que me motivara a desarrollar PirannaFS y Gaia (y que no subiera el codigo a la forja hasta el ultimo momento... :-P En Git los branchs y forks son cosas de cada dia, pero en SVN son casi como invocar a
Cthulhu...), y por ultimo continuar con el desarrollo de libGaia, Uranus y PyMite4Multiboot ya durante el verano o bien durante el año que viene, esta vez ya centrandome en darles una consistencia y una calidad al codigo, principalmente haciendo que funcione correctamente la memoria dinamica y el funcionamiento en espacio de usuario (aunque la tentacion de aprovechar PyMite para hacerme un sistema operativo y un kernel en Python me esta rondando mucho la cabeza... :-P ).

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