Entropie anthropique

Aller au contenu | Aller au menu | Aller à la recherche

mardi 7 octobre 2008

Suite des appels bloquants huilés en extension C/Ruby

Disclaimer: ce post contient un hippopotame claudiquant et ne dois pas être pris comme une bonne manière d'écrire son code ou penser une architecture.

Bon, je n'ai pas fait de code propre à juste compiler et démarrer pour la preuve du hack, mais voici comment il faut procéder. A noter qu'il faut être un peu au fait des extensions C pour Ruby, je vous laisse chercher sur la toile, il y a peu d'articles mais on les trouve facilement.

Tout d'abord on crée une socketpair avec Ruby (on peut le faire en script).

        int skt1, skt2;
        VALUE sp, s1, s2;
        ID id_socketpair = rb_intern("socketpair");
        ID id_SOCK_STREAM = rb_intern("SOCK_STREAM");
        ID id_Socket = rb_intern("Socket");
        ID id_UNIXSocket = rb_intern("UNIXSocket");
        ID id_ivar_socketpair = rb_intern("@@socketpair");
        ID id_fileno = rb_intern("fileno");

        sp = rb_funcall( rb_const_get( rb_mKernel , id_UNIXSocket ),
                         id_socketpair,
                         2,
                         rb_const_get( rb_const_get(rb_mKernel, id_Socket ) , id_SOCK_STREAM ),
                         INT2FIX(0));

        s1 = rb_ary_entry( sp, 0 );
        s2 = rb_ary_entry( sp, 1 );

        s1 = rb_ary_entry( sp, 0 );
        s2 = rb_ary_entry( sp, 1 );

        /* get the fileno */
        skt1 = FIX2INT(rb_funcall( s1, id_fileno, 0 ));
        skt2 = FIX2INT(rb_funcall( s2, id_fileno, 0 ));

A partir de là, on peut lire et écrire dans les sockets skt1 et skt2, l'une est à réserver au thread de la librairie C qui bloque, l'autre est là pour le thread principal contenant ruby lui-même. Les lectures / écritures doivent être agrémentées d'un protocole perso, compliqué au possible (puisque vous devez faire attention aux sockets qui craquent, que la quantité de donnée lue est la bonne, la façon de la représenter, les signaux qui interrompent la lecture etc.). Elles servent également de synchronisation si besoin.

Du côté de Ruby, on peut soit tout faire en script avec un appel a la méthode kernel "select". En version C ça donne une boucle avec un truc comme

                        ret = rb_funcall( rb_mKernel, id_select, 4, fds, Qnil, Qnil, INT2FIX(1) );

Avec ret une VALUE qui sera Qnil s'il n'y a rien à lire. Le id_select c'est rb_intern("select"), le fds est un array contenant une des valeurs s1 ou s2 lors de la création de la paire de sockets. Le INT2FIX(1) à la fin, c'est le timeout en secondes.

A bien noter qu'un thread doit écrire et lire dans le même socket, vu qu'on lit d'un côté et écrit de l'autre, parfois on se mélange les pinceaux et on y comprend plus rien. Pour résumer, en C les "seules" choses qu'on a vraiment à faire c'est: avoir un thread qui fasse les appels bloquants si nécessaire (risque de devoir faire de la synchronisation supplémentaire) et signale à travers un protocole. Les parties "socketpair" et "select" écrites en C peuvent être faites en script, seule la partie qui ressort un "int C" après un appel à "fileno" est nécessairement à l'interface des deux langages.

Ouf, on y est, je crois que les gens qui auront suivit jusqu'ici sauront deviner les petits pièges, et le hack très moche qu'un tel workaround représente, mais bon, tant qu'on aura pas de threads systèmes, il va falloir faire avec les d'hippopotames claudiquants :) . A réserver pour les petites quantités de données à copier et les trucs "simples". Autant dire pas souvent ^^.

A noter que j'ai surtout fait se post car j'étais déterminé à trouver un workaround au problème, plus qu'à proposer un truc sérieux. Là, il faudrait que je me mette à lire tout les mécanismes de l'intérieur du Ruby officiel de Matz.

samedi 3 mai 2008

Ubun-tue

J'ai voulu tester les capacités de la si renommée Ubuntu, du coup je l'utilise depuis environ deux mois. Voici mes impressions.

  • l'installation m'avait parue longue pour ce que c'était, charger un live-cd pour ensuite installer, pourquoi pas mais c'est pas ce qui me serait venu à l'esprit
  • certains paramètrages par défaut étaient invivables, par exemple le driver Synaptics : impossible à configurer correctement (j'ai du le désactiver en éditant le xorg.conf à la main)
  • la carte son n'était pas reconnue dès le départ, sans raison particulière car il "suffit" d'éditer une configuration alsa (à la main)
  • après un mois, un mois et demi d'usage, les fenêtres s'ouvrent systématiquement en plein écran, alors que je voudrais qu'elles s'ouvrent comme on les a laissées. Impossible de trouver ou configurer ça dans l'ignoble Gnome, je suis arrivé à modifier ce comportement pour Nautilus seulement, en éditant la base de registre Gconf. Malgré tout, le settings a quand même sauté.
  • si on active les "effets jolis" de compiz-fusion, alors le terminal clignote dès qu'il signale une "erreur", c'est à dire qu'il devient invivable d'utiliser Vim dans un terminal (par exemple): si on fait echap une fois de trop le machin vous arrache les yeux, il "suffit" d'installer l'application d'édition des effets de compiz et de trouver la bonne case (je vous laisse chercher)
  • le packaging à la debian qui sépare toujours en 12000 paquets un logiciel, ses headers etc. font que pour compiler un truc, il faut chercher quinze ans les bons headers, mais ça ce doit être une question de goût, perso je pense que la place occupée par les headers etc. est négligeable pour le public visé par Ubuntu et pourraient être livrés avec
  • finalement, mise à jour laborieuse avec la nouvelle version "support à long terme", les settings ont encore sauté, les touches du clavier pour changer le volume ne marchent plus (il y a bien le pop-up carré avec le volume qui s'affiche, mais la barre de volume reste figée), les bips systèmes ont été restaurés, le fuseau horaire a sauté également
  • sans compter les nouvelles applications plus beugguées que les anciennes (au pif, l'aperçu des espaces de travail qui montrent des fenêtres inexistantes), merci le choix des packages
  • les outils d'administrations me laissent perplexe, par exemple l'outil réseau sert à quoi et à qui ? pourquoi on a "scan de ports" dans un cas et "traceroute" dans l'autre, il n'y a aucune cohérence, dans le choix des noms et le placement de ces outils. D'ailleurs ça sert à quoi au lambda, aux "êtres humains" (car Ubuntu c'est Linux for human beings) ? à priori à rien, et pour ceux qui ont besoin de scanner leur réseau, bah en général ils utilisent nmap car on y met les options qu'on veut.

En conclusion, Ubuntu me laisse une impression d'avoir un système qui tourne mais impossible à configurer, tout du moins sans ligne de commande. C'est en contradiction avec la publicité qu'en font ses fan-boys. Pour avoir déjà utilisé OpenSuse ou Mandrake (c'était pas encore Mandriva), j'dois dire qu'Ubuntu est encore loin derrière les standards d'il y a deux ou trois ans. En tout cas je ne la recommanderai pas à un débutant, et non plus à un développeur. A la limite KUbuntu ou XUbuntu (donc sans Gnome) pourrait être moins pire, mais ne comptez pas sur moi pour faire le test. D'ici la fin du mois, Ubuntu giclera. Ça tombe bien, la nouvelle Slackware est sortie, et je dois aussi tester ArchLinux et Frugalware.

Oui, Ubuntu "just works", c'est à dire qu'il marche à peine.

lundi 28 avril 2008

Comment changer le comportement de "new" dans ruby

Oui, c'est vrai, on utilise initialize nous dit Pouype, mais on peut tout à fait bidouiller avant de créer une instance en tournant autour de "new", voici le code:

 1 class Truc
 2   class << self #construction magique pour que "self" devienne la classe Truc qu'on est en train de créer, car alias marche sur les méthodes d'instances
 3     alias :oldnew :new
 4   end
 5   
 6   attr_accessor :bidule
 7
 8   def Truc.new
 9    p "salut"
10    t = Truc.oldnew #l'instance est créée maintenant là tout de suite, pas avant pas après
11    t.bidule = :chose
12    t #si on ne retourne pas t, alors ce sera :chose qui sera retourné
13   end
14 end
15
16 p Truc.new.inspect

Pour le commentaire, je dirais que c'est juste une preuve du concept, la méthode la plus propre est de créer une méthode de classe du style Truc.new_avec_prout qui à son tour appellera Truc.new .

Pour ceux qui se demandent comment ça se fait qu'on puisse faire ça, c'est qu'il n'y a pas de magie dans Ruby, les concepts de classes/objets/instances ne font pas d'exception à la règle (à ma connaissance). C'est entre autre pour cette raison que Ruby est un peu lent, mais ça prouve qu'il est cohérent et reste un joujou trop génial.

dimanche 27 avril 2008

Projets Ruby qui seraient bien

En vrac, et sans trop plus d'explications:

- un DSL pour générer des parsers de stream (avec possibilité de rajouter ses propres templates pour le langage de son choix)

- plein de scripts pour faire de la recherche / du tri d'information dans les gros volumes

- continuer Férus pour coder des petits jeux simplements

- conquérir le monde à l'aide de deux souris au génie génétique

- des librairies "à la" graphviz pour sortir du .svg

samedi 8 mars 2008

Ruby Mate Stachine is out

Yet, you've found a mate for your state machines in ruby, namely stachine. It's a Ruby class which enables in a rubyesque way the declaration of state-machine classes. It's easy to use and under the same license than Ruby. Feel free to use it (e.g. in a stream parser, Markovian process simulation etc.) and let me know your thoughts.

Get it at http://rubyforge.org/projects/stachine/

Sample code
 1 #!/usr/bin/env ruby
 2
 3 require 'stachine.rb'
 4
 5 class MyMachine < MateStachine
 6   
 7   def initialize
 8     @state = :initial
 9   end
10
11   state :initial, :second do 
12     def reset
13       puts "Reset done"
14       @state = :initial
15     end
16   end
17
18   state :initial do
19     def button_A
20       puts "A button pressed, changing state"
21       @state = :second
22     end
23   end
24
25   state :second do
26     def button_A
27       puts "A button pressed, remaining in this state"
28     end
29   end
30
31 end
32
33 m = MyMachine.new
34 3.times do |t|
35   m.button_A
36 end
37 m.reset
38 m.button_A
Output

A button pressed, changing state

A button pressed, remaining in this state

A button pressed, remaining in this state

Reset done

A button pressed, changing state

lundi 12 novembre 2007

Android, le Gphone, un joli projet d'informatique embarquée

Android c'est la plateforme de développement de téléphones libres fraîchement sortie par Google.

Il y a une séparation bien pensée entre l'affichage et le moteur des applications. Il y a SQLite, WebKit, WiFi, Bluetooth bref, plein de choses qui sont très prometteuses. Il y a vraiment tout, mais j'ai l'impresson qu'ils ont oublié qu'un téléphone doit aussi faire ... téléphone. En fait linux est un bel OS, mais il n'est pas tout à fait prêt pour le "real-time" demandé par des applications téléphoniques. En effet, la norme POSIX n'est pas une norme créée dans ce but. Il faut bidouiller linux pour avoir un semblant de temps-réel, mais la vidéo n'en parle pas, de même qu'elle ne parle presque pas des piles de protocoles de la téléphonie :(. J'ai l'impression qu'ils ont oublié un truc.

Bon, j'irai jeter un coup d'oeil à leur SDK en tout cas. La première vidéo est par là (en anglais) : http://youtube.com/watch?v=Mm6Ju0xhUW8 .

Pourquoi utiliser Ruby ?

Il y a beaucoup de langages de programmation, un nombre immense de façons de programmer et un autre innombrable d'utilisation des langages. Je vais tenter de donner mon point de vu sur Ruby. Pour resituer les choses, Ruby est un langage de programmation dynamique orienté objet.

Ruby est connu pour Ruby On Rails (RoR), mais ses détracteurs (ceux de RoR) répondent que Ruby n'est pas performant. C'est un peu vrai, Ruby n'est pas un langage très rapide. D'ailleurs, je ne pense pas que ce soit sont but. Là où Ruby est efficace, c'est la fabrication d'outils, et j'ajouterais bien la génération de code.

Grâce à sa syntaxe naturelle, Ruby permet de coder agréablement du code sans s'arracher les cheveux. Sa gestion des classes les blocs de code et la métaprogrammation permettent de se fabriquer des "modèles" de méthodes. Dès qu'il faut établir des relations entre des classes qui dépassent le simple "héritage" des langages objets, c'est d'une intensive utilité. Le fait que le langage YAML (vraiment pratique pour les configurations) et qu'un serveur web soient dans le package de base rajoutent à la douceur du langage. De même, un outil intuitif de templates (ERB) est présent par défaut, ce qui fait de Ruby une boîte à outil complète est légère pour les programmeurs.

Et je pense que Ruby devrait continuer à se concentrer sur ce point, et ses utilisateurs phares, faire des librairies qui vont dans ce sens. Je ne pense pas qu'on arrive à imposer RubyOnRails, car les programmeurs sont un peu fainéants d'apprendre un frameworks aussi dense, mais il n'en reste pas moins que Ruby permettra de faire des applications connectées par dessus HTTP (avec la simplicité dont on écrit une requêtes HTTP et SOAP).

Pour l'avenir de ruby je verrais bien: - un exporteur de fichiers SVG - un générateur de code C pour parser des fichiers binaires étant donné leur "schéma" - un vrai truc, sans trop de dépendances, pour faire des GUI (Shoes à l'air intéressant)

Ruby-istes, unissons-nous !

lundi 22 octobre 2007

C'est quoi l'entropie ?

Faut bien expliquer un peu pourquoi mon blog s'appelle "entropie anthropique", non ?

Lire la suite