Archivo para la categoría ‘Sistemas Operativos’

La forma “fácil” de compilar el kernel de Linux en Ubuntu

Como frikis geeks de la informática que somos, si usamos cualquier sabor de GNU/Linux, puede que algún día nos entre el gusanillo de compilar nuestro propio kernel.

La forma menos fácil es bajarse los fuentes con git, configurarlo con make menuconfig, compilarlo con make y luego copiar los archivos donde corresponda. Una búsqueda en Google y nos dará todos los tutoriales que queramos.

Pero los usuarios de Debian y derivados, entre ellos Ubuntu, tenemos una forma mucho más sencilla de hacerlo:

  1. Instalamos los paquetes necesarios que incluyen el código fuente del kernel y las herramientas para compilarlo:

    $ sudo apt-get install build-essential kernel-package linux-source libncurses5-dev

  2. Descomprimir el código fuente que acabamos de instalar:

    $ cd /usr/src
    $ tar -xjf linux-source-version.tar.bz2

  3. Configurar nuestras propias opciones del kernel:

    $ cd linux-sources-version
    $ make menuconfig

  4. Crear un paquete Debian (*.deb) con el nuevo kernel (esto tardará un poco porque tiene que compilarlo). El comando make-kpkg debe ejecutarse como root, de ahí el fakeroot, aunque también se puede ejecutar con sudo con un poco de cuidado:

    $ fakeroot make-kpkg --initrd --append-to-version=nuestra-versión kernel-image kernel-headers

  5. Instalar nuestro nuevo kernel:

    $ cd ..
    $ sudo dpkg -i nombre-de-nuestro-kernel.deb

  6. Si todo ha ido bien, tendremos nuestro kernel instalado con su correspondiente entrada en el menú de GRUB. En caso de que no esté en GRUB, se debe ejecutar el comando update-grub.

Además de con los fuentes de los repositorios, también se puede hacer con los fuentes que se bajen de git teniendo en cuenta que el parámetro --append-to-version es necesario (sino puede que de el error package xxx not in control info).

Un truco: para acelerar un poco la compilación, se puede indicar a make-kpkg que lance varios procesos en paralelo. Para ello hay que exportar la variable CONCURRENCY_LEVEL con el número de procesos máximo a utilizar.

$ export CONCURRENCY_LEVEL=4

Hay que tener en cuenta que esta variable no debería ser superior al número de procesadores/núcleos del ordenador porque caería el rendimiento.

Luego, por supuesto, hay que reiniciar el sistema y elegir en la pantalla de GRUB nuestro nuevo kernel mirando que no hayamos metido la pata al configurarlo.

Y esto es todo. Si hay algún error (que lo habrá) lo ponéis en comentarios y también si os ha funcionado, si habéis obtenido mejor (o peor :P ) rendimiento, si no funcionaba…

Mi presonalizado comando less

El comando less es una utilidad de los sistemas UNIX (cualquier sistema operativo compatible con POSIX lo debería tener) que sirve para ver los contenidos de los archivos de forma completa, pudiendo navegar entre dichos contenidos y consumiendo muy pocos recursos.

El comando less puede personalizar su salida, es decir, se puede incluir información adicional del archivo que se está viendo en la visualización del mismo, como el nombre del archivo, el tamaño, en qué posición nos encontramos, etc.

Por defecto la información mostrada es escasa, por lo que una pequeña personalización nunca viene mal. A continuación os dejo la que yo tengo en mi sistema:

alias L='less -NR -P "?f%f:<stdin>.?m (%i/%m). [%s bytes] %lt/%L (%pB \%) ?x-> ?x%x"'

Más o menos muestra el número de cada línea, el nombre del archivo abierto o <stdin> en caso de que sea la entrada estándar, la página en la que estás, el tamaño, el porcentage en el que te encuentras y el siguiente archivo pasado a less (en caso de que haya).

Así, con less tienes más información de lo que estás viendo. Por supuesto esto es totalmente personalizable, así que un poco de man less no viene mal para saber como mejorarlo ;) .

En este caso, Linux es mejor que Windows

Es curioso que vaya a ver el vídeo del nuevo iPhone 4G desde Chrome en Windows y me diga, sin sorprenderme, que necesito QuickTime para poder reproducirlo. Y el famoso QuickTime viene con iTunes de regalo.

Lo divertido de esto es que desde Chrome en Linux basta con hacer clic en el mismo para verlo insertado en el navegador o, si no estás conforme (yo no lo estaba porque no tenía controles de pausa, avanzar ni retroceder), basta con hacer clic con el botón derecho y darle a la opción “Ver en el reproductor”.

Por supuesto, hay que tener los extra codecs, pero instalarlos es inmensamente menos doloroso que bajarse el QuickTime, instalarlo y encontrarse con que iTunes ahora controla toda tu música.

En este caso (y no es aislado), Linux gana a Windows ;) .

Actualización a Ubuntu 10.04 Lucid Lynx

Imagen de inicio de Ubuntu 10.04

Hoy me he actualizado a Ubuntu 10.04 desde la versión anterior, la 9.10, mediante el actualizador automático, y me he encontrado con algún que otro problemilla:

  • Ha tardado casi cuatro horas. Esto no es un problema realmente, pero entre las descargas y la instalación con dpkg se ha tirado un buen rato. Bien es cierto que tengo unos cuantos paquetes de desarrollo como gcc, g++, apache, mysql,…
  • Después de instalar, en el reinicio, no se me veían los bordes de las ventanas, con lo que no las podía mover, ni cerrar, ni nada. Eso era porque al darle a instalar tenía activado Compiz, y en el reinicio se desactivó. Para solucionarlo, basta con ir al Menú principal > Sistema > Preferencias > Apariencia y ahí, en la solapa Efectos visuales, seleccionar cualquiera que no sea el básico (luego ya se configurará al gusto) para activar de nuevo Compiz.
  • En otro ordenador que también instalé, tuve el problema de que en el reinicio no cargó correctamente el tema Ambiance ya que yo tenía un tema personalizado. Basta con seleccionar de nuevo el tema a aplicar en Menú principal > Sistema > Preferencias > Apariencia y listo.

Por cierto que el cambio de los marrones a los morados y grises me parece muy acertado; excepto, por supuesto, el cambio de los botones de las ventanas de la derecha a la izquierda (y estuve un rato probándolos, pero no me apaño). Para cambiarlos, en la aplicación gconf-editor se va a la ruta /apps/metacity/general/button_layout y se cambia el texto close,minimize,maximize: por el texto menu:minimize,maximize,close.

A parte de esto, ningún problema. Eso sí, eso de los 10 segundos en arrancar todavía les queda un poco lejos. Cierto es que arranca rápido, más rápido que la versión anterior, pero que no se echen tantos faroles. Esperemos que la próxima versión sea la vencida.

The Ubuntu Manual

Ubuntu Manual Project

Acaba de salir The Ubuntu Manual, un proyecto que intenta crear un manual para el sistema operativo Ubuntu, una distribución de GNU/Linux.

En este manual se encuentra la información que un usuario final necesita para hacerse con el sistema, desde el principio, es decir, desde la instalación en un equipo hasta la configuración del mismo pasando por la información necesaria para el manejo de las aplicaciones que usamos en el día a día, como un navegador Web, un cliente de correo electrónico, etc. Además, por supuesto, de mantenimiento del sistema e instalación de software adicional.

Pero lo mejor, quizás, es que está en español (y en unos cuantos idiomas más), capturas de pantalla incluidas. El problema es que todavía no está en español :( .

A nivel de usuario, creo que es lo que faltaba para que la adopción de otros sistemas operativos empiece a despuntar. Bien es cierto que con Windows tampoco teníamos manual, digamos que aprendimos “de oídas”, así que ahora que tenemos oportunidad, creo que es buena idea ponerse con esto y empezar, no quizás a eliminar por completo la otra alternativa, pero sí a probar para ver, al menos, qué es lo que nos estamos perdiendo.

Si vuestro uso del ordenador es el de un usuario normal, es decir, más o menos, navegar por Internet, leer el correo electrónico, chatear, editar documentos de texto y hojas de cálculo, ver presentaciones, escuchar música y ver vídeos1, os animo a todos a probar Ubuntu, que tiene manual, o cualquier otra distribución de GNU/Linux.

1 Por supuesto se pueden hacer muchas más cosas que estas, esto sólo es el principio.

Creando pthreads en Linux (y sus problemas)

Hoy toca otra vez de esos tostones informáticos que no interesan a nadie, como el de GCD, pero que lo pongo para hacer copia de seguridad de estas pequeñas investigaciones.

Estoy haciendo un proyecto donde tengo que utilizar multiproceso para que varias tareas se ejecuten simultáneamente (nunca mejor dicho) que consiste en conectar a varios equipos lanzando varios hilos para que el intento de conexión a uno no haga esperar las conexiones a los demás. Una vez lanzados todos se espera por ellos hasta que terminen de conectar para iniciar el resto del proceso.

El desarrollo es en Linux y en C++ y todo el proceso está dentro de una sola aplicación, es decir, no hay varias aplicaciones que se lanzan desde una shell de forma simultánea, no, es una única aplicación desde donde está todo el proceso, por eso no se pueden usar varios procesos sino que se usan hilos, exactamente pthreads.

Los pthreads son el estándar POSIX para hilos de ejecución. Además, también definen la sincronización de los mismos mediante mutex y variables de condición (que, por cierto, nunca he entendido su funcionamiento; yo uso semáforos).

Para facilitar la mantenibilidad del software, he implementado toda la funcionalidad mediante orientación a objetos, incluidos los hilos, semáforos, mutex, etc., por lo que para iniciar un hilo, se haría de la siguiente forma:

class MyThread : public Thread {
public:
MyThread() : Thread {}
virtual ~MyThread() {}
virtual void* run(void* arg) {
cout << “MyThread::run()” << endl;
}
};

MyThread* thread = new MyThread();

thread->start();
thread->wait();

delete thread;

Dentro de la función start() se crea un pthread y se inicia mediante la función pthread_create(...). En la función wait() se espera por el hilo hasta que finalice su ejecución mediante la función pthread_join(...).

La clase Thread cuenta también con funciones para parar un hilo, reiniciarlo, etc. También se puede pasar como parámetro la función a ejecutar o, incluso, una clase que herede de la clase ThreadFunction que tiene la función run() para que así esta implementación sea bastante polivalente.

Hasta aquí todo bien. La verdad es que funciona de forma bastante estable, creo que es sencillo de utilizar (al menos es lo que pretendo) y bastante mantenible ya que cualquier modificación afecta sólo a la clase y apenas hay que tocar el resto de código.

Pero, a partir de aquí, en cuanto se empieza a hacer un uso intensivo, es cuando comienzan los pequeños problemas.

Resulta que la función pthread_create() no sólo crea un nuevo pthread sino que también lo inicia, es decir, no hay ninguna función que sea pthread_start(), sino que para iniciar (y parar) un hilo hay que crearlo (y destruirlo). Además, los desarrolladores de los pthreads no están por la labor de hacer estas funciones.

El problema surge cuando se crean muchos hilos e inmediatamente después se espera por ellos, por ejemplo, de la siguiente forma:

#define limit 100

MyThread* threads[limit];
for(int i = 0; i < limit; i++) {
threads[i] = new MyThread();
threads[i]->start();
threads[i]->wait();
}

// no hay que olvidarse de destruirlos

El problema está en hay veces que se crea un hilo dando como resultado un pthread_t válido (el identificador del hilo), pero no da tiempo a iniciarlo antes de que se ejecute el pthread_join(), por lo tanto se está haciendo una espera sobre un hilo creado pero no iniciado. En teoría pthread_join() debería devolver un valor del tipo EINVAL o similar pero no. En la práctica lo que se produce es un fallo de segmentación, es decir, corrupción de memoria.

Para reproducir esta funcionalidad, he hecho un pequeño programa en C++ que, ejecutado varias veces, produce este comportamiento incorrecto. En este caso no he conseguido corrupción de memoria, pero tampoco es está completo.

La solución que se me ocurre es usar un semáforo que sincronice la creación y la iniciación del hilo con la espera del mismo. No es una solución demasiado elegante pero creo que funcionará.

La verdad es que el API de POSIX respecto a hilos no me parece demasiado buena, pero creo que no tengo nada que hacer. Es en estos momentos es cuando hecho de menos el API de hilos de BeOS/Haiku ;) .

ASUS Eee PC y Windows Starter

El otro día se compró mi hermano un ASUS Eee PC 1001 con Windows 7 Starter (en una tienda muy conocida y al precio standard).

El equipo en sí está muy bien. Es pequeño, no hace ruido, apenas se calienta, con una pantalla brillante y nítida y suficientemente grande como para navegar perfectamente por Internet, leer el correo electrónico, ver vídeos, leer libros,… por supuesto, todo para uso personal. En el momento que aparece otra cabeza para ver la pantalla ya se está demasiado cerca… aunque a veces hasta es mejor :P .

Pero el sistema operativo, Windows 7 Starter… bueno, eso mejor insertáis una unidad USB, arrancáis y lo formateáis completamente. Porque Windows 7 Starter da verdadero asco.

Que sí, que vale, que está hecho para dispositivos con poca potencia, pero no, no es normal que no se pueda cambiar el fondo de pantalla. Sí, habéis leído bien: en Windows 7 Starter no se puede cambiar el fondo de pantalla.

Y, a parte de esto, tampoco tiene la interfaz Aero (cosa casi lógica, si quieres), ni hay previsualizaciones de las ventanas en la barra de tareas, no reproduce DVD (ni con un DVD externo), no se puede cambiar entre usuarios sin cerrar sesión y ni siquiera tiene el modo de compatibilidad con Windows XP. Vamos, completito, completito. Y no, no es por las capacidades del hardware. Es pura política.

De verdad, hay veces que confías y dices “vaya, por fin han hecho un producto que funciona” y ahora van y la cagan con esta mierda.

Hibernando el sistema en Linux (y solucionando algún que otro problema)

La hibernación es una característica de los sistemas operativos que permite que toda la memoria RAM se copie al disco duro de forma que, en el próximo reinicio del sistema, se cargue la memoria RAM del archivo previamente guardado sin necesidad de realizar el inicio del sistema de forma normal.

Con esto se consigue que no sea necesario cerrar ninguna sesión ni ningún programa que esté en ella y, la próxima vez que se arranque el ordenador, todas las aplicaciones estarán en el mismo estado que cuando lo hibernamos.

En Linux disponemos de esta opción desde el menú de apagado de la interfaz gráfica, por lo que basta hacer clic en el botón correspondiente para que nuestro sistema hiberne.

Pero, además de esta opción, en los sistemas Linux también tenemos un comando que realiza esta acción: hibernate.

Con este comando conseguimos hibernar el sistema desde una consola o desde un script de apagado automático de la máquina, para que en el próximo reinicio tengamos todas nuestras aplicaciones abiertas.

Pero la función hibernate no está exenta de sus riesgos. A mi los errores que me daba eran principalmente dos:

El primero es que si había varias hibernaciones seguidas, esto es, según termina de iniciar el sistema después de una hibernación realizar otra (mediante el comando), en el segundo reinicio después de esta hibernación, se producían errores en las aplicaciones debido a fallos de segmentación en alguna de las librerías que usaba (las que vi fueron libc.so y libdbus.so).

Me inclino a pensar que después del reinicio no sabía exactamente donde estaban localizadas las librerías en memoria y por eso fallaba. O, quizás el kernel de Linux tenga una función de posicionamiento aleatorio del código para evitar ataques y todavía no funciona todo lo bien que debería. Pero, como digo, esto son suposiciones. Además, después de un poco de uso normal, en las siguientes hibernaciones todo iba perfectamente.

El segundo de los problemas se producía con GRUB 2, el nuevo gestor de arranque que traen las distribuciones de Linux más modernas (en mi caso Ubuntu 9.10). GRUB 2 tiene un registro llamado recordfail que se fija a uno cuando el sistema arranca y a cero cuando se apaga correctamente. Si se apaga incorrectamente y recordfail queda a uno, en el siguiente reinicio no aparece el timeout del menú de inicio del sistema por lo que hay que seleccionar el sistema operativo a arrancar manualmente.

Con el comando hibernate, una vez que inicia de nuevo el sistema, no fija de nuevo la variable recordfail de GRUB 2 a uno, con lo que en los siguientes reinicios después de hibernar, siempre hay que seleccionar el sistema a arrancar de forma manual.

Para solucionar esto, hay que configurar el comando hibernate. El archivo de configuración, como es norma en sistemas Linux, está en /etc/hibernate/hibernate.conf. En este archivo hay que añadir las siguientes líneas:

LockGnomeScreenSaver true
OnResume 00 /etc/pm/sleep.d/10_grub-common thaw

La primera línea bloquea la sesión de Gnome con su salvapantallas (porque tampoco lo hace por defecto con lo que después del reinicio aparecía la sesión sin contraseña; un gran fallo de seguridad) y la segunda línea indica que se ejecute el archivo /etc/pm/sleep.d/10_grub-common con el parámetro thaw, que es el archivo que fija recordfail a cero en cada inicio correcto del sistema.

Con esta pequeña solución, ya tenemos el comando hibernate listo para incluir en nuestro script de apagado automático sin que tengamos que arrancar todas las aplicaciones en cada reinicio.

Formateando

Disco Duro

Ayer me compré un disco duro externo por USB de 1,5 TB para las copias de seguridad y demás, pero lo compré por separado (caja más disco) y, lógicamente, lo tuve que formatear en casa.

Y el caso es que para esos 1,5 TB, el Windos XP Home que venía en el portátil tardó, nada más y nada menos, que ¡¡5 horas!! en formatear en NTFS. Lo cual me inclina a pensar que si llego a comprarme uno de 3 TB, hubiera tardado 10 horas ¿no? Estupendo este NTFS.

Ahora no lo voy a probar (5 horas son demasiado para repetirlo) pero me gustaría ver cuánto hubiera tardado con ext4 o, por probar, con btrfs. Con BFS, por ejemplo, hubiera tardado menos de un minuto (o poco más) ya que hace poco más que escribir la información del disco y el mapa de bits de espacio libre.

Pero es lo que tenemos que aguantar si queremos que funcione tanto en Windows como en Linux (y sí, ya se que hay soluciones para que desde Windows podamos leer ext2 y ext3, pero no me fío demasiado).

Comunicación entre procesos

A la hora de desarrollar un sistema operativo, después de haber planificado la gestión de memoria y la gestión de procesos e hilos, le toca el turno a la comunicación entre los distintos procesos, IPC en inglés, imprescindible para el funcionamiento del sistema.

Para la comunicación a bajo nivel (en el kernel) entre hilos existen varias técnicas que se pueden resumir en:

  • Memoria compartida: Varios procesos, aunque en espacios de memoria distintos, comparten una zona de la misma donde leen y escriben los datos a compartir. La ventaja es que se pueden compartir grandes cantidades de datos y es un sistema muy rápido y sin problemas para lecturas. En cambio, existe el problema de la sincronización del acceso cuando varios procesos tienen que escribir en la misma zona de memoria simultáneamente.
  • Paso de mensajes: Es un sistema donde, mediante canales compartidos entre los procesos, éstos leen y escriben para comunicarse. Se suele implementar mediante sockets, pipas y FIFO‘s aunque hay más tipos de implementación. La ventaja es que las lecturas y escrituras son síncronas por lo que no hay problemas de lectura y escritura simultáneas. El problema es que la cantidad de datos a comunicar puede estar limitada.

El sistema operativo BeOS y su sucesor, Haiku, han implementado una solución muy elegante: por un lado, como los sistemas compatibles con POSIX tiene la compartición de memoria; por otro lado, implementó dos técnicas adicionales:

  • El paso de mensajes entre hilos directamente mediante las funciones send_data(...) y receive_data(...) con el inconveniente de que las funciones son síncronas y después de enviar el primer mensaje, hasta que no se lee no se puede enviar otro.
  • El paso de mensajes mediante puertos. Los puertos son el homólogo a los sockets pero entre procesos y mucho más rápidos. Existe un elemento común entre dos hilos llamado “puerto” a través del cual los procesos se comunican mediante las funciones write_port(...) y read_port(...). La ventaja de esto es que el puerto puede tener un buffer por lo que, hasta que no se llene, las llamadas a estas funciones son asíncronas.

Con estas dos técnicas, se consigue tanto la comunicación entre procesos como la sincronización entre distintos hilos gracias a que las llamadas a las funciones de lectura y escritura son síncronas.

Debido a que este tipo de comunicación, aunque muy rápida, es bastante complicada de aplicar, sobre todo porque los datos pasados entre los distintos procesos no tienen tipo, son flujos de bytes, se han implementado otras técnicas de comunicación, pero estas a nivel de aplicación, es decir, no es el proceso el que responde, sino la aplicación completa mediante una API dedicada a ello.

Algunos ejemplos de estas implementaciones son RPC, MPI, COM, DCOM, DDE, OLE, CORBA, ICE, D-Bus, DCOP, MBUS, RMI, Sockets, Doors, OpenBinder, etc.

En esta lista hay que destacar OpenBinder. OpenBinder es una implementación de un nuevo tipo de comunicación entre procesos. Este proyecto nació con lo que iba a ser la siguiente versión de BeOS, la 6, aunque posteriormente maduró dentro de Palm al ser esta empresa la que compró los derechos sobre BeOS.

OpenBinder está un nivel por encima del resto de implementaciones de comunicación entre procesos. Y digo un nivel por encima porque esta API proporciona una comunicación, por decirlo de alguna forma, a nivel de componentes, es decir, los componentes del sistema operativo, incluyendo los componentes de la interfaz gráfica (ventas, botones, etc.) son clases que heredan de clases de OpenBinder, con lo que cualquier componente es susceptible de comunicarse con cualquier otro. Este sistema inicialmente implica bastante complejidad, pero está optimizado para ser muy rápido y, además, lo que se pretende con él es poder hacer aplicaciones, especialmente GUI‘s como las X, que sean distribuidas de forma transparente para el desarrollador.

OpenBinder no merecería más atención que la del resto de sistemas si no fuese porque esta tecnología está implementada dentro del sistema operativo Android, dejando de lado el resto de sistemas. Esto es cuanto menos curioso, ya que el resto de tecnologías están ampliamente probadas y esta, quizá, sea la más nueva. Pero aquí es donde se ve lo que gasta Google en I+D; no se conforma con lo que hay, quiere lo mejor (según ellos, claro).

Y ya puestos, se pueden empezar a hacer conjeturas: por ejemplo, los dispositivos Android completos podrían estar en la nube de Google, no sólo los datos que manejan, por lo que tu teléfono móvil o tu ordenador podrá ayudar a Google a procesar sus propios datos.

Ahora hay que esperar un poco más a que salga Chorme OS para ver qué sistemas de comunicación tiene y saber si esta teoría será real o una simple paranoia mía :) .

Analizando GCD

Hace unos meses que Apple sacó a la venta la última versión de su sistema operativo, Mac OS X 10.6 Snow Leopard.

Esta versión es principalmente una versión de, como dicen ellos, afinamiento. No se han incorporado características nuevas sino que se han refinado las actuales dándole al sistema una mayor velocidad y estabilidad. Lo que sí han hecho es incorporar en el núcleo del sistema una tecnología que no se ve pero que sí se nota: Grand Central Dispatch.

Logotipo de Grand Central Dispatch

GCD es una nueva tecnología que lo que hace es distribuir las tareas que tienen que hacer las aplicaciones en tareas más pequeñas para así aprovechar toda la potencia de las máquinas que tienen varios procesadores o varios núcleos por procesador, como viene siendo habitual en los ordenadores de hoy en día, no sólo los Apple.

Esta tecnología viene a solucionar el problema de la escasez de paralelismo con la que contaba Mac OS X, pero, más que por su incapacidad, por la desidia de los desarrolladores a incorporarlo en sus aplicaciones. Aunque tienen sus razones, claro, es bastante complicado sincronizar hilos cuando no tienes un API que te ayude a hacerlo.

GCD añade dos cosas al nuevo sistema operativo de Apple. La primera es lo que se conoce como un pool de hilos, es decir, en lugar de que cada vez que queramos realizar una acción de forma paralela creando un hilo para así aprovechar los diferentes procesadores, lo que hacemos es indicar al sistema que queremos realizar tareas paralelas. Es el propio sistema el encargado de crear los hilos correspondientes y de ejecutarlos con una de las tareas a realizar.

La diferencia con los hilos tradicionales es que los hilos de GCD ni se crean ni se destruyen (esto me suena), simplemente existe una o varias listas de estos hilos (el pool) donde cada tarea se va a asociando a cada uno de estos hilos hasta que termine. Una vez terminada la tarea, el hilo no se destruye, sino que vuelve a la lista correspondiente. Además, estas listas de hilos tienen diferentes prioridades con lo que se puede tener más precisión a la hora de ejecutar tareas.

Lo bueno que tiene esto es que el programador no tiene que preocuparse de nada más que de indicar cuáles son las tareas a realizar de forma paralela. El sistema se encargará de distribuirlas entre las distintas listas de hilos disponibles.

Pero para lograr esto, Apple se ha tenido que sacar de la manga una extensión para el lenguaje C de su compilador Clang. Esta extensión es lo que se conoce en otros lenguajes, como Java o Javascript, como closures. Las closures son funciones anónimas o funciones lambda, algo así como los punteros a funciones de C pero con capacidades extras, como el acceso a variables locales, que se puedan devolver por otra función o que se puedan declarar en línea.

A esto, los desarrolladores de Apple le llamaron bloques. Entonces un bloque sería un trozo de código ejecutable que se parece a una función pero que no tiene nombre (función anónima) y que puede acceder a las variables locales del ámbito donde se ha declarado. Y la sintaxis que han hecho es al mejor estilo de C: austera. Veamos unos ejemplos, aunque la forma de trabajar es similar a Java y Javascript pero con distinta sintaxis:

// bloque asignado a una variable y accediendo
// a una variable local
int b = 3
multiplicar = ^ int (int a) { return a * b; };

// x valdría 6
int x = multiplicar(2);

// declaración de un tipo de bloque
typedef void ( ^ my_block_type)(int count);

// función que repite la ejecución de un bloque n veces
void repeat(int times,my_block_type block) {
for(int i = 0; i < times; i++) {
block(i);
}
}

// declaración en línea (pasando como parámetro
// un bloque completo sin declararlo previamente
// como se hace con los punteros a funciones)
repeat(10, ^ (int count) {
printf(“count = %d\n”,count);
});

Gracias a esta nueva extensión, con apenas trabajo por parte del desarrollador, se puede aprovechar toda la potencia de las máquinas multiprocesador. Y, realmente, cuando se dice con “pocas líneas” es cierto. Basta con identificar las tareas (ese es el trabajo difícil) y usar las funciones dispatch_* de la nueva API pasando como parámetro un bloque de código con la tarea a ejecutar. Es el sistema, de forma transparente, el que se encarga de distribuir las tareas en los distintos procesadores creando los hilos necesarios para ello o utilizando los que están en el pool.

La verdad es que hay que agradecer a Apple que por fin se pusiese las pilas en cuanto al rendimiento de sus sistema, que ya iba bien de por sí, pero siempre puede ir mejor, sobre todo por facilitar el paralelismo de tareas a los programadores. Y aunque esto está muy bien, todavía no he visto por ningún sitio cómo han solucionado el problema de la sincronización/comunicación entre tareas (a parte de la memoria compartida y semáforos, claro), ya que esta extensión es sólo para aprovechar las máquinas multinúcleo.

Y es que, a mi entender, creo que esta solución que tan bien les está yendo, es un parche para un problema que viene de lejos. Venga, va, aquí los abucheos por criticar el Mac OS X. Pero expongo mis razones:

Esta solución crea un pool de threads con los que, a partir de un momento dado, se empiezan a realizar tareas sin la necesidad de estar creando y destruyendo hilos continuamente sino reaprovechándolos. Existe más de un pool con diferentes prioridades para así gestionar mejor las tareas. Esta solución es así porque la forma en Apple que implementó los hilos en Mac OS X no es la de lightweight threads (hilos ligeros) sino la de hilos más parecidos a procesos que a hilos en sí.

Esta solución implica que la creación de cada hilo sea bastante costosa, aproximadamente unos 512 KB por cada uno, mientras que la solución de hilos ligeros, la que implementan BeOS y Haiku (sí, ha salido BeOS, ¿raro en este blog? :) ) es la de verdaderos hilos ligeros, con lo que la creación de los mismos apenas lleva 50 KB (32 KB de memoria de pila y el resto de estructuras internas del kernel).

512 KB por hilo creado es mucha memoria utilizada. Y más teniendo en cuenta la cantidad de aplicaciones y servicios que se están ejecutando en un sistema operativo actual según se inicia. Por pocos hilos que crees estás consumiendo mucha memoria y hay que tener en cuenta que cuantos más hilos (ojo, con un límite), más paralelismo y mayor aprovechamiento del hardware. Y vale que ahora la memoria es barata, pero ¿los nuevos sistemas funcionarán en hardware antiguo? Quizás esto no sea una prioridad para Apple, pero siempre hay que pensar en todo.

Como comenté antes, tampoco sé exactamente como se sincronizan las tareas en Mac OS X, mientras que en BeOS/Haiku tenemos tres mecanismos muy ligeros para ello: semáforos, comunicación entre hilos y puertos. El problema es la complejidad a la que se enfrenta el programador para hacer esta sincronización, aparentemente solucionada en Mac OS X, pero que no debería ser un problema si existe una buena API dentro del sistema que lo facilite.

En conclusión (y ya para terminar este ladrillo de entrada) creo que Apple ha mejorado mucho su sistema con esta característica, tanto para los usuarios, aprovechando el hardware al máximo, como para los programadores, haciendo que con escasas líneas de código aprovechen mejor dicho hardware, pero sigo pensando que la solución inicial de hilos pesados no es tan buena como la solución de hilos ligeros.

¿Para cuándo se podrán grabar las llamadas en Android?

Hay una aplicación que hecho mucho de menos en el sistema operativo Android, y es la aplicación que grabe las conversaciones.

Quizás no la hayan hecho porque violaría la privacidad de dichas conversaciones, pero hay que reconocer que puede llegar a ser muy útil. Siempre que se avise de la grabación se puede usar en un juicio (esperemos que, por nuestro bien, no llegue a ser necesario), pero si no lo vas a usar y es para uso personal, en teoría no habría que avisar de ello ¿no? Pero ¿sería legal?

De todas formas, la parte que me interesa es la tecnológica. Creo que en el API de Android no es posible interceptar una llamada más lejos de saber quién es el que llama, por lo que la grabación de la misma, al menos de momento, no es posible. De todas formas, sí que tiene una clase y una constante, MediaRecorder.AudioSource.VOICE_CALL, para grabar voz (indica que se graba la voz de entrada y de salida, esto es, la del que llama y la del que es llamado), de donde se puede intuir que si se podrá en un futuro.

Además, esto sería extremadamente útil para hacerte tu propio contestador automático dentro del propio teléfono sin contar con los servicios de contestador de las operadoras. Y, por supuesto, es software libre, podemos ir mucho más allá con esta característica. Algo así como una mini centralita Asterisk con todas las posibilidades que ello conlleva.

Y ya que estamos interceptando llamadas, también sería muy buena idea sacar otra aplicación que, entre dos terminales con el mismo software, se pudiesen cifrar dichas conversaciones. De hecho sería buena idea ya que hay quién avisa de que tengamos cuidado con lo que se habla por el teléfono.

Supongo que tarde o temprano lo harán. Es, como dicen en algunos foros, un must have, una aplicación imprescindible. Ahora esperemos que sea más pronto que tarde.

Ya tengo mi Android 1.6

Desde esta mañana, a eso de las nueve y media, ya tengo en mi HTC Magic la actualización de Android a la versión 1.6 (ellos la llaman Donut) a través de las actualizaciones automáticas vía telefónica (en inglés es OTA; siempre poniendo siglas…).

La actualización no ha durado más de cinco minutos reiniciando dos veces y todo funcionando sin problemas.

Ahora a disfrutarla1 hasta que llegue la 2.0, también conocida como Eclair, a finales de año (esperemos ;) ).

Actualización: De momento, a falta de investigar un poco, tengo un fallo con esta nueva versión y es que no se reciben automáticamente los correos electrónicos que llegan a la cuenta de Gmail. Para recibirlos hay que realizar una sincronización manual. He revisado la configuración de sincronización y está todo en automático. He reiniciado y tampoco. Los mensajes de Gmail con Android 1.6 no se reciben en tiempo real. Si alguien sabe algo que comente por aquí.

Actualización 2: Como dije antes, no actualiza en tiempo real. La última prueba que he hecho me ha tardado 12 minutos desde que envié el correo hasta que lo he recibido en el terminal.

Actualización 3 (22/10/2009): Parece que los problemas no son del terminal ni de la actualización sino que son de la funcionalidad de Push email de Vodafone o de Google. Supongo que retrasarían el envío de correos para mejorar la avalancha de descargas de Donut. Ahora parece que todo funciona.

1 Venga, va, algunos se preguntarán «¿cómo se puede disfrutar una versión de software?». Bueno, a los que somos Ingenieros Informáticos por vocación nos pasan estas cosas. Es lo mismo que sientas pasión por cualquier otra cosa, como los coches, la ropa, las antigüedades,… la única diferencia es que lo nuestro no es tangible.

Primeras impresiones de Haiku R1/Alpha1

Iniciando Haiku OS

Como comenté ayer, me he bajado la versión R1/Alpha1 de Haiku —el sistema operativo libre cuyo objetivo es hacer un clon de BeOS 5— lo he tostado en un CD y lo he arrancado en el portátil como Live CD sin llegar a instalarlo. El portátil es un Pentium M a 1,8 GHz con 1 GB de memoria RAM y una tarjeta gráfica ATI con memoria compartida (no recuerdo cual).

El inicio del sistema fue como la otra vez, muy lento. Aproximadamente tardó cinco minutos en estar disponible el entorno. Eso sí, hay que tener en cuenta que se estaba iniciando desde un CD-ROM.

Una vez iniciado el sistema, el entorno es el de siempre. Digo siempre porque es casi igual, con algún retoque estilístico, al del BeOS r5, incluidas sus aplicaciones. Lo que me ha sorprendido gratamente es que el sistema es muy rápido. En cada acceso al CD para cargar aplicaciones, tardaba un rato, como cualquier lectura de disco, pero una vez que estaban cacheadas, el inicio, cierre y funcionamiento de las aplicaciones es muy fluido. No había paradas momentáneas del ratón, ni menús que tardasen en abrir, ni ventanas que parpadeasen.

Con varias aplicaciones abiertas, entre las que estaban BeZillaBrowser, ActivityMonitor, DriveSetup, Pulse y la ventana de créditos, el consumo de la CPU se mantiene en niveles mínimos, un 4% aproximadamente, siendo ActivityMonitor la aplicación que más consume ya que se actualiza unas 10 veces por segundo. La memoria RAM usada con estas aplicaciones apenas pasó de 150 MB.

Haiku ejecutándose (foto)

Durante toda la prueba (que principalmente ha sido la carga de aplicaciones y ver si funcionaba la multimedia) no me ha fallado ninguna aplicación. Todas ellas se han iniciado sin problemas y no hay sido necesario matar ninguna. Incluso cuando he cambiado las opciones del media_server, el reinicio del mismo ha sido rápido e indoloro. El sonido, con un driver AC97, funciona sin problemas, así como el vídeo con los formatos soportados (aunque la arquitectura multimedia es específica —y muy buena, por cierto—, usa ffmpeg para decodificar vídeo y audio).

'Acerca de Haiku' en mi ordenador

Tampoco hubo ningún problema al fijar las opciones del teclado soportando el mapa del español (con la ñ y los acentos). En cambio el idioma y las opciones locales todavía no han sido implementadas (estas opciones se conocen como Locale) aunque en versiones previas y en la lista de discusión sí que estaban los inicios de esta característica.

Lo que me sorprendió un poco y no me gustó nada es que el ventilador del ordenador estuvo a bastante velocidad durante toda la prueba aun siendo el consumo de CPU mínimo. ¿Será quizás porque no ha funcionado correctamente el ACPI? Espero que lo solucionen en la próxima versión.

El cierre del sistema, un shutdown sin cerrar ninguna aplicación de las antes mencionadas antes de hacer el apagado, ha tardado menos de 5 segundos hasta que pone la ventana de que ya se puede apagar el sistema con seguridad (de momento no se apaga sólo, como hacía BeOS).

Ya para terminar, la impresión de esta versión pública de Haiku ha sido excelente. Ha sido como cuando comencé con BeOS allá por el año 2000, con entusiasmo. Además, como habréis notado, la palabra que define esta versión es velocidad, lo que me ha sorprendido gratamente (aunque en el fondo quizás lo esperaba).

Ahora hay que darle más apoyo y seguir trabajando para llegar a la versión 1.0 y después de que cale en la comunidad, a por la versión 2.0 donde ya se haría un desarrollo de un sistema operativo moderno. Eso sí, probablemente no sería compatible con BeOS. De hecho, principalmente para la versión 2 habría que implementar el sistema multiusuario y la seguridad. Pero bueno, tiempo al tiempo. A ver si con este hay más suerte que con el BeOS.

Actualización 17/9/2009: Según este mensaje de la lista de correo de Haiku, Haiku sí soporta APM/ACPI pero, por el momento, está desactivado ya que no están todas las funcionalidades implementadas. Se puede activar editando un archivo del sistema pero hay que tener cuidado porque ciertas BIOS cuando detectan que el ACPI está manejado por el sistema operativo, también se desentienden de los ventiladores para que el sistema operativo haga lo propio. Y esta es una de las carencias de Haiku, todavía no tiene implementado el control de ventiladores, así que, de momento, hay que tener cuidado con la activación del ACPI.

Ya está disponible Haiku R1/Alpha1

Acerca de Haiku

Por fin se ha anunciado la disponibilidad de Haiku en su versión R1/Alpha 1 en versiones .iso, imagen de disco e imagen de VMWare.

Además, este anuncio coincide con la remodelación de su página Web que pasa de que predomine el color blanco a que predomine el color azul (no es un cambio muy significativo pero viene bien como campaña de marketing).

Ahora hay que bajarla, probarla, y dar otra pequeña reseña como hice hace un par de semanas; eso sí, no hay que olvidar que es una versión alpha y que todavía queda mucho para una beta y para la versión final.

Haiku en hardware real (mi ordenador)

Ya están disponibles imágenes .iso para descargar de la primera versión candidata (RC) de Haiku Alpha 1.

Como ya hice en su momento cuando salió una versión previa no oficial en LiveCD, la he probado y, esta vez sí, ha funcionado:

Haiku OS corriendo en mi ordenador (hardware real)

Mis primeras impresiones son que ha tardado muchísimo en arrancar. Hay que tener en cuenta que fue desde un CD, pero, aún así, ha tardado más de 3 minutos.

El interior es igual que BeOS, simple, sencillo y rápido. Las aplicaciones que tiene funcionan bien excepto alguna que me dio algún error (la configuración del ratón, que era USB y él sí funcionó a la primera) y el media_server no consiguió arrancar. Tampoco me reconoció la tarjeta de red (que es Wifi).

En cambio acertó de pleno con la configuración de la pantalla a 1280×1024 y cuando arranqué la tetera (la famosa aplicación Teapot en 3D) conseguía 140 fps. Además, la memoria usada por el sistema era de unos 100 MB al finalizar el arranque y la carga del procesador siempre se mantuvo al mínimo.

Creo que para una alpha 1 es suficiente, pero creo también que les falta mucho trabajo para llegar a la beta. Eso sí, confío en que al sacar esta alpha más gente se anime a probarlo y más gente se anime a desarrollar para él, sobre todo los entusiastas del BeOS. A ver si esta vez hay más suerte.