News fin mai début juin 2008

Splitch splatch flock

Flock a récupéré 15 millions de dollars dans un round Serie D, par Fidelity Ventures (qui comprend déjà les investisseurs précédents Bessemer Venture Partners, Catamount Ventures et Shasta Ventures).

Flock est un browser Internet orienté « social » construit sur le code de Firefox. Flock se définit comme intégrant plusieurs sites de réseaux sociaux et des services directement inclus dans le navigateur avec, par exemple, MySpace, Facebook, YouTube, Twitter.

Le nombre d’utilisateurs de Flock a augmenté de 250% depuis janvier de cette année, avec un bénéfice qui a augmenté de 400% sur la même période. Flock a été nommé comme gagnant du « Webby Award », catégorie « Réseau Social », battant Facebook et Bebo.

Flock a dit que l’argent investi allait servir à étendre le business de Flock, notamment le département recherche et développement, le marketing et l’expansion dans des marchés plus génériques.

Twitter

Twitter a terminé un tour de table qui a levé 15 millions de dollars, ce qui amène sa valeur à 80 millions de dollars, a affirmé GigaOm.

Des rumeurs circulent depuis des mois, expliquant que Twitter tente de faire d’autres levées de fonds, et certains sons de cloche laissaient entendre que de tour de table a été plusieur fois repoussé principalement parce que Twitter était plutôt radin et tentait de se faire évaluer à quelques 200 millions de dollars, donc plus personne ne voulait miser.

J’ai aussi trouvé quelque part sur un site (je ne souviens pas où) que le fait que Twitter ait eu des gros problèmes pour s’étendre (manque de souplesse) (« scaling failure ») ne voulait rien dire parce que même les personne qui se plaignaient n’auraient pas quitté ce service de toute manière, ce qui n’est pas mauvais, mais il y a un énorme espoir sur le fait que quelques 15 millions de dollars seront investis afin de pouvoir garder toujours ce service en fonctionnement, et qu’il puisse mieux grossir. Comme Twitter se veut la plateforme de prédilection pour le microblogging, la plupart des compagnies qui proposent des services autour de Twitter sont principalement des sociétés qui proposent un service en-ligne 24/7, pardonnez du peu.

Ce nouveau tour amène les investissements dans Twitter à une hauteur de 20 millions de dollars.

Napster

Napster amène ce qu’il appelle « le plus grand magasin de mp3’s au monde ».

Le vendeur de musique en ligne vient tout juste de lancer sa base de fichiers mp3’s libres de droits, ce qui veut dire que les chansons seront compatibles avec n’importe quel programme, player, ou autre, capable de jouer des mp3’s (qui ne le fait pas aujourd’hui ?).

« Les fans de musique ont parlé et c’est clair qu’ils veulent un format mp3 libre de DRM, et ce, aussi bien chez le plus gros labels de distribution que chez les artistes indépendants, le tout à un seul endroit », affirme Chris Gorog, directeur PDG de Napster.

Napster dit que son nouveau magasin fait plus d’une fois et demi la taille de n’importe quel autre vendeur de m3’s en ligne, avec plus de six millions de chansons à disposition. Celles ci sont vendues à un prix allant de 0,99 dollars l’un jusqu’à 10 dollars pour l’album entier.

Micro$oft

Microsoft lance un nouveau programme qui va vous payer si vous utilisez son site de recherche.

“Microsoft Live Search Cash Back” fonctionnera avec eBay et PayPal pour offrir aux utilisateurs du cash lorsqu’ils achèteront des produits qu’ils auront trouvé via Microsoft Live. De partout, les réductions iront de 30 pourcent jusqu’à 100 % (le prix entièrement remboursé sur votre compte eBay ou PayPal !). Barnes and Noble, Sears, et Home Depot sont déjà présents parmi les résultats de recherche.

Microsoft va vous demander de créer un acompte pour avoir ces reversements.

Le discours officiel de Microsoft ressemble à : “Nous cherchons à nous différencier via des expériences verticales, et à casser le modèle courant”.

Traduction de notre technicien spécialiste dernières technologies : “Nous sommes tellement désespérés que les internautes ne passent que par Google qu’on en arrive à leur offrir un peu d’argent pour les aider à changer leurs habitudes”.

Immobilier et business

Si Zillow est le meilleur endroit (Anglais) pour ceux qui veux acheter un bien immobilier personnel, ZoomProspector espère devenir le meilleur endroit pour ceux qui veulent faire des transactions sur des commerces, en fournissant des informations géographiques importantes et des conseils sur l’endroit où ils veulent construire/acheter leur(s) commerce(s).

ZoomProspector fait un melting-pot d’informations sur les villes, régions et alentours – par exemple le taux de chômage, le nombre de travailleurs, le niveau moyen d’éducation, l’investissement fait dans l’immobilier, et une moyenne des loyers – et toutes ces informations sont accessibles via un seul et unique outil de recherche à l’intérieur d’une carte.

La recherche avancée sur google : les pages récentes

Article original en Anglais ici.

Une des astuces les plus pratiques dans la recherche avancée de Google est le filtre « date », qui limite les résultats aux pages trouvées récemment. Les résultats peuvent être limités au dernier jour, à la dernière semaine, mois, années, etc.

Matt Cutts, de Google, et GoogleOperatingSystem en ont parlé en fin d’année dernière.

Vous pouvez accéder à ce filtre via l’URL, directement, en ajoutant simplement “&as_qdr=d” à la fin de n’importe quelle requête : comparez les deux résultats : Apple et Apple uniquement aujourd’hui. Changez simplement le « =d » en d5 pour 5 jours, ou w5 pour 5 semaines (w=weeks), ou y5 pour 5 ans, etc.

Librairie Apr : tutoriel : fichier flock-sample.c

Note

Regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.
Ce fichier exemple vient d’ici.

/**
 * Exemple pour le tutoriel apr
 * http://dev.ariel-networks.com/apr/
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <apr_general.h>
#include <apr_file_io.h>

static apr_status_t do_writelock(const char *fname, apr_pool_t *mp)
{
    apr_status_t rv;
    apr_file_t *fp;

    if ((rv = apr_file_open(&fp, fname, APR_WRITE, APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
        return rv;
    }
    rv = apr_file_lock(fp, APR_FLOCK_EXCLUSIVE | APR_FLOCK_NONBLOCK);
    /* si vous mettez le drapeau APR_FLOCK_NONBLOCK, apr_file_lock() ne fonctionnera pas.
     * Il faut toujours vérifier la valeur de retour */
    if (rv != APR_SUCCESS) {
        puts("writable-lock failed");
        goto done;
    }
    printf("%s est verrouillé en écriture.\n", fname);
    printf("Appuyez sur une touche pour le déverrouiller.\n");
    getchar();

    apr_file_unlock(fp);
 done:
    apr_file_close(fp);
    return rv;
}

static apr_status_t do_readlock(const char *fname, apr_pool_t *mp)
{
    apr_status_t rv;
    apr_file_t *fp;

    if ((rv = apr_file_open(&fp, fname, APR_READ,  APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
        return rv;
    }
    rv = apr_file_lock(fp, APR_FLOCK_SHARED | APR_FLOCK_NONBLOCK);
    if (rv != APR_SUCCESS) {
        puts("Impossible de mettre le verrou en lecture.");
        goto done;
    }

    apr_file_unlock(fp);
 done:
    apr_file_close(fp);
    return rv;
}

/**
 * Exemple de verrou fichier
 * @remark Vérif. des erreur supprimée pour plus de clarté
 */
int main(int argc, const char *argv[])
{
    apr_status_t rv;
    apr_pool_t *mp;
    int c;
    const char *fname;

    if (argc < 2) {
        printf("Utilisation : %s fichier-de-sortie\n", argv[0]);
        return 0;
    }
    fname = argv[1];

    apr_initialize();
    apr_pool_create(&mp, NULL);

    puts("verrou-écriture / verrou-lecture [w/r]?");
    c = getchar();
    if (c == 'w') {
        rv = do_writelock(fname, mp);
    } else if (c == 'r') {
        rv = do_readlock(fname, mp);
    }

    apr_pool_destroy(mp);
    apr_terminate();
    return 0;
}

Librairie Apr : tutoriels : 6 et 7

6. Les verrous sur les fichiers

Lorsqu’on veut verrouiller des fichiers entre processus, il faut utiliser apr_file_lock(). Historiquement, des confusions se sont installées concernant le verouillage sur Unix. C’est pourquoi le fait de n’avoir que deux fonctions simples grâce à la librairie libapr est très appréciable.

/* extrait de apr_file_io.h */
APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type);
APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile);

apr_file_lock() demande deux arguments. Le premier est un objet apr_file_t. Le second est un drapeau (« flag »), qui sert à spécifier les blocages qu’on veut imposer (« lock type »). Il peut être soit APR_FLOCK_SHARED, soit APR_FLOCK_EXCLUSIVE. We can use the former as a readable lock, and the latter as a writable lock. Pour déverrouiller le fichier, il suffit d’appeler apr_file_unlock(). Ou bien le fait d’appeler apr_file_close() le déverrouille implicitement. Regardez flock-sample.c pour savoir comment faire.
De plus, il est possible d’utiliser un paramètre composé de drapeaux (« bitwised-or flag ») en précisant APR_FLOCK_NONBLOCK. Sans le flag APR_FLOCK_NONBLOCK, apr_file_lock() est bloquant. Avec ce flag, APR_FLOCK_NONBLOCK, si apr_file_lock() ne peut pas verouiller un fichier, il ne bloque pas et renvoie immédiatement un code erreur : APR_EAGAIN.
Il faut toujours s’assurer que la valeur de retour de apr_file_lock() est APR_SUCCESS. Si c’est le cas, le fichier a été verouillé avec succès. Sinon, il n’a pas pu être verouillé.

7. Gestion des répertoires dans le système de fichiers

Quand on veut faire quelque chose avec des répertoires, il faut toujours appeler d’abord apr_dir_open(). Après cet appel, on a un objet apr_dir_t. La seule chose que l’on puisse faire avec un objet apr_dir_t est de parcourir le répertoire. La fonction à utiliser est apr_dir_read(). A la fin on appelle apr_dir_close() pour fermer le répertoire. Ci-suivent les déclarations de la librairie :

/* extrait de apr_file_info.h */
APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new_dir,
    const char *dirname, apr_pool_t *pool);
APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo,
    apr_int32_t wanted, apr_dir_t *thedir);
APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir);

Le premier argument de apr_dir_open() est un argument résultat. C’est grâce à lui qu’on récupère l’objet apr_dir_t qui est crée. Le second argument est le nom du répertoire. Le troisième est le nom du pool mémoire à utiliser.
Le premier arguement de  apr_dir_read() est un argument résultat. Comme mentionné précédemment, apr_finfo_t est un type complet. Donc il faut l’allouer explicitement. apr_dir_read() renvoie une entrée du répertoire  apr_finfo_t. L’entrée est soit un fichier soit un répertoire. Le second argument est une aggrégation de drapeaux (« bit-wised flag »). Ces drapeaux sont définis dans apr_file_info.h. Ils ont tous le préfixe APR_FINFO_, par exemple APR_FINFO_SIZE, APR_FINFO_TYPE et APR_FINFO_NAME. Le troisième argument est l’objet apr_dir_t à parcourir.

Voici un code d’exemple :

/* pseudo code expliquant apr_dir_read() */
/* no error checks */
apr_pool_t *mp;
apr_pool_create(&mp, NULL);
/* répertoire à scanner */
const char *dirpath = "/home";
apr_dir_t *dir;
/* créer l'objet apr_dir_t */
apr_dir_open(&dir, dirpath, mp);
apr_finfo_t dirent;
/* remplir l'objet apr_finfo_t */
apr_dir_read(&dirent, APR_FINFO_DIRENT, dir);
/* dirent est la première entrée du répertoire.
 * Cette entrée est soit un fichier soit un répertoire. */
apr_dir_close(dir);

Dans l’exemple au-dessus, on appelle apr_dir_read() une seule fois, mais habituellement on le fait en boucle pour énumérer tous les fichiers d’un répertoire. Pour ce faire, il suffit juste d’appeler apr_dir_read() tant qu’il renvoie APR_SUCCESS. Regardez l’exemple qui est plus parlant : dir-sample.c.

/* pseudo code sur la boucle apr_dir_read(). Vérif. des erreurs omise */
/* Boucle typique de apr_dir_read() */
apr_dir_open(&dir, dirpath, mp);
while ((apr_dir_read(&dirent, APR_FINFO_NAME, dir)) == APR_SUCCESS) {
    printf("Le nom est %s\n", dirent.name);
}
apr_dir_close(dir);

Comme vous pouvez l’imaginer, la position courante du répertoire est stockée dans l’objet apr_dir_t. Le fait d’appeler apr_dir_read() fait avancer la position d’un cran. On peut reculer cette potision (qui est interne) en appelant apr_dir_rewind(). Les seules opération que l’on peut faire avec la position sont ces deux là : aller en avant et aller en arrière.

Comme vous pouvez le voir dans dir-sample.c, si vous scannez un répertoire de manière récursive, vous devez appeler apr_dir_open() de manière récursive, ici aussi.

REMARQUE : Sur Unix, apr_dir_read() renvoie un objet apr_finfo_t dont la propriété apr_file_t::fname est NULL.

Librairie Apr : tutoriel : finfo-sample.c

Note

Regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.
Ce fichier est l’exemple le plus simple pour mettre en oeuvre les fonctions apr_xx
Il vient d’ici.

/**
 * Tutoriel apr, exemple de code
 * http://dev.ariel-networks.com/apr/
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <apr_general.h>
#include <apr_file_io.h>

/**
 * exemple de récupération d'informations sur un fichier
 * @remark Vérif. des erreurs omise
 */
int main(int argc, const char *argv[])
{
    apr_status_t rv;
    apr_pool_t *mp;
    apr_file_t *fp;
    const char *fname;
    apr_finfo_t finfo;

    if (argc < 2) {
        printf("Utilisation : %s fichier-de-sortie\n", argv[0]);
        return 0;
    }
    fname = argv[1];

    apr_initialize();
    apr_pool_create(&mp, NULL);

    /* @remark depuis apr-1.1.0, utiliser APR_FOPEN_READ au lieu de APR_READ */
    if ((rv = apr_file_open(&fp, fname, APR_READ, APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
        return -1;
    }

    /* Ci-suivent deux façons différentes pour récupérer
     * l'information : elles donnent le même résultat.
     *
     * Si vous avez déjà ouvert le fichier,
     * le premier est le meilleur. Sinon, le
     * second est le meilleur.
     */

    /* Récupération des informations. Via apr_file_t */
    rv = apr_file_info_get(&finfo, APR_FINFO_NORM, fp);
    /* Récupération des informations. Via le nom de fichier */
    rv = apr_stat(&finfo, fname, APR_FINFO_NORM, mp);

    apr_file_close(fp);

    apr_terminate();
    return 0;
}

Librairie Apr : tutoriel 5

5. Gestion des fichiers

Quand on veut des opérations dans un fichier, il faut en premier lieu appeler apr_file_open(). Voilà la déclaration :

/* extrait de apr_file_io.h */
APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **newf,
    const char *fname, apr_int32_t flag,
    apr_fileperms_t perm, apr_pool_t *pool);

Le type du premier argument est apr_file_t**, qui est un argument résultat. Plus précisément, il stocke l’objet apr_file_nouvellement crée lors de l’appel à apr_file_open(). Le second argument est le répertoire + nom du fichier. Le troisième est une composition de flags, définis dans apr_file_io.h. Le quatrième argument est le type de permission qu’on accorde sur ce fichier, mais cela ne fonctionne que lors de la création de fichier. Les flags sont définis dans apr_file_info.h. Par exemple, si vous voulez créer un fichier dont les permissions d’accès sont 0600, c-à-d. lecture-écriture uniquement autorisée par le possesseur du fichier, il vous faudra spécifier APR_UREAD|APR_UWRITE. Vous utiliserez le plus couramment APR_OS_DEFAULT comme permission. Le cinquième et dernier argument est le pool mémoire à utiliser. Précisons pour le lecteur occasionnel que le pool mémoire aura été crée auparavant via apr_pool_create().
Après qu’on ait ouvert le fichier, on peut l’utiliser pour d’autres fonctions de la librairie apr. On peut trouver ces fonctions dans apr_file_io.h. Les fonctions les plus basiques sont apr_file_read() et apr_file_write(). Comme vous l’imaginez, apr_file_read() donne la possibilité de lire quelque chose du fichier et apr_file_write() d’écrire quelque chose dedans.Voilà les déclarations :

/* extrait de apr_file_io.h */
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile,
    void *buf, apr_size_t *nbytes);
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile,
    const void *buf, apr_size_t *nbytes);

Le troisième argument des deux fonctions est un argument en entrée mais aussi en sortie (= résultat). En entrée, il sert à spécifier la longueur de la valeur, et on a en sortie le retour du nombre d’octets résultant de l’opération. Pour simplifier, apr_file_read() renvoie le nombre d’octets lus, et apr_file_write() renvoie le nombre d’octets écrits. Voici un code d’exemple.

/* pseudo-code expliquant apr_file_write() */
strcpy(outbuf, "123456789");
apr_size_t outlen = strlen(outbuf);
rv = apr_file_write(fp, outbuf, &outlen);
printf("apr_file_write() rv = %d, nb octets = %d\n", rv, outlen);

Dans ce cas, avant d’appeler apr_file_write(), la variable ‘outlen’ vaut 9. En passant &outlen à apr_file_write(), on dit à la librairie qu’il faut écrire 9 octets. Au retour de apr_file_write(), la valeur de ‘outlen’ est remplie de ce qui a été effectivement écrit. Habituellement c’est 9, surtout si c’est un fichier local. En théorie, la valeur pourrait être plus petite (si le disque est plein par exemple).
Il faut toujours appeler apr_file_close() pour fermer le fichier. Il est possible aussi de le fermer automatiquement en détruisant le pool mémoire par lequel il a été crée, mais je préfère fermer mes fichiers de manière explicite. Cela n’engage que moi.

REMARQUE : Il y a quelques incompatibilités entre les différentes versions de la librairie libapr. Le troisième argument de apr_file_open() a comme préfixe APR_FOPEN_ depuis libapr-1.1.0, alors que ce n’était pas le cas avant. Il faut donc utiliser APR_FOPEN_CREATE au lieu de APR_CREATE. Consultez apr_file_io.h pour voir ce qu’il vous faut réellement utiliser. De la même façon, le quatrième argument de apr_file_open() a le préfixe APR_FPROT_ depuis la libapr-1.1.0.

REMARQUE : Il y a un problème de portabilité sur le séparateur des répertoires/noms de fichiers. Unix(POSIX) utilise le slash (‘/’), et les systèmes Microsoft utilisent le backslash (‘\’) en tant que séparateur. Si vous voulez écrire une application qui tourne sur les deux système, je vous conseille de transformer toujours les séparateur en slash (‘/’) car les systèmes Microsoft l’acceptent quand même.

REMARQUE : Faites attention lors du l’utilisation de apr_file_gets(). Faire un appel à cette fonction sans le paramètre APR_BUFFERED dégrade sérieusement les performances de l’opération. Cela s’explique par le fait que apr_file_gets() appelle apr_file_read(), et, sans ce paramètre, il y aura un appel pour chaque octet à lire. Souvenez vous bien qu’il vous faut ouvrir le fichier avec le flag APR_BUFFERED si vous voulez utiliser apr_file_gets().

Je vous recommande d’utiliser toujours APR_BUFFERED sauf dans ces cas :

  • Quand vous « mmap »-ez le fichier (cela génère une erreur du fichier à « mmapp-er ») ;
  • Aucune lecture/écriture (p.ex. un fichier destiné à être uniquement un verrou) ;
  • Vous êtes sûr que vous lisez ou écrivez avec un buffer suffisamment gros.

REMARQUE : Si vous ouvrez un fichier avec le flag APR_BUFFERED et que vous appelez par la suite apr_file_trunc(), n’oubliez pas d’appeler apr_file_flush() avant apr_file_trunc(). Sinon vous allez perdre des informations.

REMARQUE: Si vous ouvrez un fichier avec le flag APR_BUFFERED, et que le fichier est partagé par plusieurs threads, il vous faut obligatoirement préciser APR_XTHREAD. Malheureusement, ce flag a quelques revers de médailles sur les systèmes d’exploitation Windows. Par expérience, je vous conseillerai d’éviter d’utiliser APR_XTHREAD sur les systèmes d’exploitation Windows.

Il est possible d’avoir des informations sur le fichier telles que la date de création, de modification, le possesseur du fichier, les permissions, etc. Ces informations sont dans la structure apr_finfo_t, que vous trouverez décrite dans apr_file_info.h. Il y a deux fonctions que fournit la librairie libapr :

/* extrait de apr_file_io.h */
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo,
    apr_int32_t wanted, apr_file_t *thefile);
/* extrait de apr_file_info.h */
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo,
    const char *fname, apr_int32_t wanted, apr_pool_t *pool);

Il faut un objet apr_file_t pour la fonction apr_file_info_get(), et un nom de fichier pour apr_stat(). Si on a déjà ouvert ce fichier et qu’on a donc un objet apr_file_t crée, c’est plus pratique de se servir de apr_file_info_get(). Sinon, il faut appeler apr_stat(). A l’inverse de beaucoup d’autres types, apr_finfo_t est un type complet. Plutôt que d’appeler une fonction de la librairie pour créer l’objet, il faut allouer une structure apr_finfo_t explicitement. Typiquement, c’est alloué sur la pile locale, parce qu’on n’a souvent besoin besoin que d’un seul attribut, comme la taille du fichier, ou sa date de création, et rien de plus. Notez que quelquefois des informations telles que apr_finfo_t::fname, sont allouées dans le pool mémoire que vous passez en paramètre. Faites attention, c’est parfois la cause de problèmes de fuites mémoire. Regardez l’exemple à finfo-sample.c pour bien comprendre le fonctionnement.

Il y a quelques fonctions de gestion des fichiers qui fonctionnent en se basant sur un nom de fichiers. Par exemple, apr_file_remove() et apr_file_copy(). Vous lez trouverez dans apr_file_io.h et apr_file_info.h.

REMARQUE : Quelques fonctions de la librairie aprlib prennent en paramètre des argument initialisés par des flags que l’on peut combiner (« bit-wised flags ») pour récupérer les attributs des fichiers. Ces fonctions sont apr_dir_read(), apr_stat(), apr_lstat(), et apr_file_info_get(). Notez que selon la valeur que vous donnez à l’argument, ce dernier peut ne pas exister sur le système d’exploitation, et dans ce cas, renvoyer la valeur d’erreur APR_INCOMPLETE.

Librairie Apr : tutoriels 3 et 4

Pour information : regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.

3. memory pool (apr_pool_t)

La plupart des fonctions de libapr sont dépendants de pools mémoire. Grâce aux pools mémoire, vous pouvez facilement gérer des groupes de portions de mémoire.

Imaginez un cas sans le système de pool mémoire, où vous devez allouer chaque portion de mémoire. Vous devez libérer chacun d’eux. Si vous avez fait dix allocations, vous devez faire dix libérations, sinon vous allez avoir des fuites mémoire. Le principe de pool mémoire résout ce genre de problème. Après avoir crée un pool mémoire, vous pouvez allouer autant de morceaux de mémoire que vous voulez sur ce pool. Pour tout libérer, la seule chose que vous ayez à faire est de détruire le pool mémoire. Le pool s’occupe de libérer le reste.

Il y a deux gros avantages :

  1. Comme expliqué juste avant, cela évite les fuites mémoire ;
  2. Ensuite, le coût machine d’allocation est réduit.

D’une certaine façon, vous devez tout de même programmer comme si vous étiez dans une session. Un pool mémoire est un peu comme un contexte de session, c’est à dire que tous les objets qui y sont liés ont la même durée de vie. Vous pouvez contrôler un groupe d’objets dans un contexte de session. Au début d’une session, vous créez un pool mémoire. Ensuite, vous créez des objets sur ce pool mémoire pendant cette session. Notez que vous n’avez pas à vous préoccuper de leur durée de vie. A la fin de la session, la seule chose que vous ayez à faire est de libérer le pool mémoire.

REMARQUE : En général, le contrôle de la durée de vie des objets est la chose la plus difficile en programmation. C’est pour cela qu’il y a plein d’autres techniques pour cela, telles que les « pointeurs intelligents, le ramasse-miettes (GC – garbage collector) etc. Il est difficile d’utiliser de telles techniques en même temps. Comme le pool mémoire est l’une de ces techniques, il vous faire attention aux mélanges !

Il y a trois fonctions principales de l’API, concernant les pools mémoire :

/* extrait de apr_pools.h */
APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, apr_pool_t *parent);
APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size);
APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);

On crée un pool mémoire via apr_pool_create(). Ce pool existe tant qu’on ne l’a pas libéré via apr_pool_destroy(). Le premier argument de apr_pool_create() est un argument-resultat. Un nouvel objet « pool mémoire », apr_pool_t, est renvoyé par cet appel à l’API. On appelle apr_palloc() pour allouer une portion de mémoire en précisant la taille. Jetez un coup d’oeil à mp-sample.c pour voir un exemple simple.

/* extrait de mp-sample.c */
apr_pool_t *mp;
/* créer un pool mémoire. */
apr_pool_create(&mp, NULL);
/* allouer une portion mémoire sur le pool */
char *buf1;
buf1 = apr_palloc(mp, MEM_ALLOC_SIZE);

En résumé, on peut utiliser apr_palloc() comme malloc(3). On peut aussi appeler apr_pcalloc(). Comme vous l’imaginez, apr_pcalloc() ressemble fortement à calloc(3). apr_pcalloc() renvoie une portion mémoire intégralement initialisée avec des zéro. Si vous vous servez de malloc(3)/calloc(3), vous aurez besoin d’appeler free(3) pour chaque portion allouée. A l’inverse, vous n’avez pas besoin de faire ça pour chaque portion allouée sur un pool mémoire. Vous appelez simplement apr_pool_destroy() avec le pool concerné et tout ce qui a été alloué est libéré.

REMARQUE : Il n’y a pas de limitation sur la taille que vous pouvez allouer avec apr_palloc(). Néanmoins, ce n’est pas une bonne idée d’allouer de gros morceaux de mémoire avec une gestion de mémoire orienté « pool ». C’est simplement parce que la gestion via un pool mémoire a été conçue pour gérer efficacement des petites allocations. En réalité, la taille initiale d’un pool mémoire est de de 8 kb. Si vous avez besoin d’allouer quelque chose de plus large, p.ex. plusieurs méga bytes, vous devriez éviter la gestion via un pool mémoire.

REMARQUE : Par défaut, un manager de pool mémoire ne libère jamais la mémoire allouée au système tant qu’il n’est pas détruit. Si un programme tourne pendant longtemps, il aura des problèmes. Je vous conseille de préciser dès le début une taille limite maximale comme suit :

/* exemple qui applique une limite haute pour forcer le
 * manager du pool à libérer de la mémoire au système
 * à partir d'un certain seuil
 */
#define YOUR_POOL_MAX_FREE_SIZE 32 /* taille max. du pool */
apr_pool_t *mp;
apr_pool_create(&mp, NULL);
apr_allocator_t* pa = apr_pool_allocator_get(mp);
if (pa) {
    apr_allocator_max_free_set(pa, YOUR_POOL_MAX_FREE_SIZE);
}

Il y a deux autres fonctions de l’API que vous devez connaitre. L’une d’elles est apr_pool_clear(), et l’autre est apr_pool_cleanup_register(). apr_pool_clear() ressemble à apr_pool_destroy(), mais le pool mémoire est toujours réutilisable. Le code typique est le suivant :

/* exemple montrant comment fonctionne apr_pool_clear() */
apr_pool_t *mp;
apr_pool_create(&mp, NULL);
for (i = 0; i < n; ++i) {
    do_operation(..., mp);
    apr_pool_clear(mp);
}
apr_pool_destroy(mp);

Le pool mémoire est utilisé dans do_operation(), qui, imaginons, alloue plein de morceaux mémoire. Si vous n’avez pas besoin de tous les morceaux alloués hors de do_operation(), vous pouvez appeler apr_pool_clear(). Ainsi vous limiterez l’utilisation mémoire. Si vous connaissez bien le principe du fonctionnement du système de la pile locale, vous pouvez imaginer que la gestion de pool mémoire est une « pile mémoire locale ». L’appel de apr_palloc() est similaire au fait de déplacer SP(stack pointer), et appeler apr_pool_clear() est similaire à faire reculer SP. Les deux opérations sont très légères en termes de calcul CPU.
La fonction apr_pool_cleanup_register() offre la possibilité d’appeler automatiquement des fonctions de libération lorsque le pool est nettoyé via apr_pool_clear() ou détruit vie apr_pool_destroy(). Dans les fonctions de callback, vous pouvez implémenter un code de libération de vos objets, ou de finalisation, liés au nettoyage/destruction du pool mémoire.
La dernière chose concernant les pools mémoire est le sous-pool. Chaque pool a la possibilité d’avoir un parent. Pour être plus précise, les pools mémoire sont organisés dans un arbre. Le deuxième argument de  apr_pool_create() est le parent du pool mémoire à créer. Si vous passez NULL en tant que parent, le nouveau pool est positionné à la racine de l’arbre. Vous pouvez créer des « sous-pools » mémoire en les liant à ce dernier. Quand vous appelez apr_pool_destroy() pour un pool mémoire dans l’arbre, tous ses descendants sont aussi détruits. Quand vous appelez apr_pool_clear(), le pool mémoire reste en vie, il est simplement nettoyé, mais les enfants sont détruits. Quand un enfant est détruit, les fonctions callback liées au nettoyage/destruction dont on a parlé précédemment sont appelées.

REMARQUE : Le bogue suivant est très courant : vous passez NULL comme paramètre pool à la fonction callback de nettoyage. Il faut plutôt utiliser apr_pool_cleanup_null, comme le montre l’exemple :

/* pseudo code sur le bogue habituel de pool mémoire */
/* apr_pool_cleanup_register(mp, CONTEXTE_DE_VOTRE_CODE, CALLBACK_DE_VOTRE_CODE, NULL); C'EST UN BOGUE */
/* Version corrigée : */
apr_pool_cleanup_register(mp, CONTEXTE_DE_VOTRE_CODE, CALLBACK_DE_VOTRE_CODE, apr_pool_cleanup_null);

4. Error status (apr_status_t)

La plupart des fonctions de la librairie libapr renvoient une valeur de type apr_status_t. La valeur apr_status_t est très souvent, soit APR_SUCCESS soit autre chose. APR_SUCCESS indique que tout s’est correctement déroulé. Le code typique ressemble à cela :

/* pseudo code sur la vérification du retour apr_status_t */
apr_status_t rv;
rv = apr_pool_create(&mp, NULL);
if (rv != APR_SUCCESS) {
    /* Gestion de l'erreur */;
}

libapr définit quelques statuts d’erreur tels que APR_EINVAL, et des macros pour vérifier des types d’erreurs telles que APR_STATUS_IS_ENOMEM((). Quelques unes d’entre elles sont vraiment très utiles, surtout pour la gestion des problèmes de portabilité. Un exemple typique est la macro APR_STATUS_IS_EAGAIN(). Historiquement, il y a deux erreurs qui ont le même chiffre mais pas la même signification, EAGAIN et EWOULDBLOCK. La macro APR_STATUS_IS_EAGAIN() gère ce problème.
Néanmoins, c’est presque impossible de gérer toutes les erreurs sans prendre en compte le système sous-jacent. La librairie libapr ne réinvente pas la roue. Ce qu’elle fait est très simple :

  • En cas de succès, retour = APR_SUCCESS
  • En cas d’erreur concernant uniquement la librarie elle-même, retour = APR_XXX
  • En cas d’erreur système commune à tous les systèmes d’exploitation, retour = APR_XXX
  • En cas d’erreur spécifique à un système d’exploitation, retour = numéro d’erreur du système plus un offset

Je vous conseille de suivre ces règles simple :

  1. Comparer la valeur de retour avec APR_SUCCESS
  2. Si vous avez besoin de plus de détails sur l’erreur, comparer avec d’autres valeurs d’erreur définies dans la librairie

Un fonction extrêmement utile est apr_strerror(). Vous pouvez afficher la chaine décrivant l’erreur de cette façon :

/* pseudo code expliquant apr_strerror() */
apr_status_t rv;
rv = apr_xxx_xxx();
if (rv != APR_SUCCESS) {
    char errbuf[256];
    apr_strerror(rv, buf, sizeof(buf));
    /* afficher la description de l'erreur */
    puts(errbuf);
}

Librairie Apr : tutoriel : aval officiel de l'auteur

J’ai eu l’aval officiel de l’auteur pour tout traduire et mettre en ligne sur mon site :
Voilà ce que j’ai demandé :

You’ve done a really really really good work with your apr tutorials.
I’d like to help the community by translating it in French and making it available in my site.
Example : (Exemple de document traduit)
May I go on or should I stop ?

Voilà sa réponse reçue au moment même où je fais cet article :

Hi, Olivier Pons,
Surely, you can go on.
It is my pleasure.
When you let me know the exact (I mean, a kind of permanent) URL, I will put the link on my site.
Thank you very much.
– INOUE Seiichiro

Pour information : regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.

La procrastination organisée

Cet article vient d’ici

J’ai essayé d’écrire cet article pendant des mois. Pourquoi est-ce que, finalement, aujourd’hui, je le fait ?

Parce que j’ai du temps libre ? Faux.

Je dois relire des documents, commander des livres, envoyer une demande de remboursement, finir de rédiger des brouillons.

En réalité je me suis mis à écrire cet article pour éviter de faire toutes ces choses. C’est l’essence même de ce que j’appelle la procrastination organisée, une stratégie impressionnante que j’ai découverte, et qui convertit les procrastinateurs en personnes efficaces, respectées et admirées pour tout ce qu’elles arrivent à faire en même temps et pour la bonne utilisation qu’elles font de leur temps. Tous les procrastinateurs, par définition, repoussent tout ce qu’ils ont à faire jusqu’au dernier moment. La procrastination organisée est l’art d’utiliser ce mauvais trait de caractère à bon escient. L’idée clé est que le fait de procrastiner ne veut pas dire « ne rien faire du tout ». Les procrastinateurs ne font rien que très rarement ; il font toujours des choses qui ne sont que peu utiles, telles que tailler des crayons, faire le jardin ou faire un diagramme de la réorganisation de leurs fichiers sur leur ordinateur. Pourquoi est-ce qu’un procrastinateur fait ces choses ? Parce qu’elles sont une façon d’éviter de faire des choses plus importantes. S’il ne restait au procrastinateur qu’à tailler ses crayons, aucune force sur la terre ne réussirait à le convaincre de tailler le moindre petit crayon. Néanmoins, le procrastinateur peut être motivé pour faire des choses difficiles, chronométrées et importantes tant que ces tâches sont des choses qui donnent la possibilité d’éviter de ne pas en faire d’autres qui sont plus importantes.

La procrastination organisée signifie « un moyen de gérer la structure même des tâches d’une manière qui exploite ce trait de caractère ». La liste des tâches qu’on a en tête doit être triée par ordre d’importance. Les tâches qui semblent plus urgentes et importantes sont au sommet. Mais il faut imaginer qu’il y a aussi des tâches importantes à réaliser en bas de la liste. Réaliser ces dernières tâches est un moyen de ne pas faire les autres, situées plus en haut sur la liste. Avec ce type de structuration des tâches, un procrastinateur devient un citoyen utile. Un procrastinateur peut même acquérir, comme moi, une bonne renommée, être efficace et paraître organisé.

La situation la plus parfaite que j’aie jamais eue, pour une procrastination structurée, était lorsque ma femme et moi travaillions en tant que professeurs à Resident Fellows dans Soto House, à Stanford. Le matin, nous avions des papiers à remplir, des interrogations à préparer, du travail qui consistait à résumer des réunions faites, et moi, je quittais à ce moment précis la résidence pour aller juste à côté jouer au ping-pong avec les résidents, ou parler de tout et n’importe quoi avec eux, dans leurs appartements, ou pire, juste rester assis à lire le journal. Je me suis fait rapidement une réputation surprenante, et on pensait que j’étais une des rares professeurs du campus qui était d’accord pour accorder du temps avec les jeunes et qui voulait mieux les connaitre. Quel truc bizarre et marrant à la fois : s’éclater au ping-pong pour éviter de faire des choses plus importantes, et acquérir la réputation du prof le plus sympa du campus !

Les procrastineurs suivent souvent une mauvaise tactique. Ils essaient de minimiser leurs engagements, assumant le fait que s’ils ont peu de choses à faire, ils vont arrêter de procrastiner et faire ces choses. C’est exactement contre la nature du procrastineur et détruit sa source la plus importante de motivation. S’il y a peu de tâches sur une liste, ça veut dire que par définition, ces tâches seront importantes, et que la seule chose à faire pour les éviter est de ne rien faire. C’est la manière la plus efficace de devenir un gros tas de gelée flasque, au lieu d’être quelqu’un d’efficace.
Arrivé ici, vous vous demandez : « Et alors, on fait quoi des tâches tout en haut de la liste, qu’au final, personne ne fait ? ». Je l’admets, il y a un problème potentiel ici.

L’astuce est de choisir vraiment bien les projets qu’on met en haut de la liste. La gestion idéale comporte deux caractéristiques : en premier, il faut qu’il y ait des deadlines (mais en réalité si ce n’est pas fait ce n’est pas la mort), et en second, il faut que les tâches semblent horriblement importantes (mais personne ne va mourir si on ne les fait pas). Heureusement, la vie abonde de tâches qui correspondent à ces deux critères. Dans les universités la grande majorité des tâches relèvent de ces deux catégories, et je suis sûr que c’est la même chose pour toutes les entreprises un peu grosses. Tenez, prenons par exemple la tâche que j’ai écrite juste en haut de ma liste maintenant. C’est de finir un essai sur le thème de la philosophe des langages. Il est supposé être terminé depuis onze mois. J’ai fait plein de choses super importantes entretemps juste pour éviter de travailler dessus. Il y a quelques mois, je me suis senti tellement coupable que j’ai écrit une lettre à mon éditeur en lui disant combien j’étais désolé d’être en retard et où j’ai exprimé mes bonnes intentions pour finir ce que j’ai commencé. Le fait d’écrire cette lettre était encore une façon d’éviter de travailler sur le sujet. Eh bien au final on a vu avec lui que mon planning était à peine derrière tout ce qu’il avait planifié. Mais en réalité est-ce que ce sujet est si important ? Pas tellement important, enfin pas important au point d’imaginer ne rien pouvoir faire d’autre. Lorsque je n’aurai plus rien à faire je m’y mettrai.

Un autre exemple est le remplissage de la fiche de commande de livres. J’ai écrit ça en juin. En octobre, je vais donner un cours sur l’épistemologie. La la fiche de commande de livres est à rendre depuis longtemps. C’est facile d’imaginer que c’est une tâche importante, avec un délai pressant derrière (pour les non-procrastineurs, je préfère signaler que les délais deviennent vraiment urgents une semaine voire deux, après que le délai soit écoulé). J’ai pratiquement tous les jours un beep de la secrétaire du département, des étudiants qui me demandent parfois ce qu’ils auront à lire, et la fiche de commande de livres est là en plein milieu de mon bureau, pile poil sous le sachet dans lequel était mon repas de midi de mercredi dernier. Cette tâche est presque tout en haut de ma liste. Cela me gêne et me motive tout à la fois, de faire d’autres choses utiles mais plus superficielles ou, disons, moins importantes. Mais en réalité, la secrétaire a une pile énorme fiches déjà remplies par des non-procrastinateurs, et elle n’a pas le temps de toutes les faire ! Je remplirai la mienne au milieu de l’été et tout ira bien. J’ai juste besoin de commander des livres connus d’imprimeurs connus et efficaces. Je vais sûrement accepter d’autres tâches apparemment plus importantes entre maintenant et, disons, le premier août. Je me sentirai mieux sur le plan comportemental si je me mets à remplir cette fiche le jour où ce sera vraiment un moyen d’éviter de faire ces autres nouvelles tâches plus importantes.

Le lecteur attentif pourra constater que la procrastination structurée demande une petite dose de déception, parce qu’il faut systématiquement mettre à jour sa propre pyramide des besoins et que celle-ci peut sembler fausse vue de l’extérieur. Parfaitement.

On doit pouvoir se reconnaitre et s’épanouir en exécutant des tâches avec une importance faussement gonflée et des délais irréalistes, tout en ressentant vraiment qu’elles sont importantes et urgentes. Ce n’est pas une difficulté en soi, parce que tous les procrastineurs ont une faculté rare : savoir se mentir à soi-même et y croire.

En conclusion : quoi de plus noble qu’utiliser les défauts d’un caractère pour les transformer en qualités ?

Joe la mouk

Oui je sais c’est vieux mais je ne m’en lasse pas.
Vous trouverez plus de choses par ici.
Ah, ils ont aussi fait la version Anglaise ici. (On sent qu’ils ont un peu d’expérience et le montage est meilleur mais celui en Français et vraiment, vraiment excellent)

Librairie Apr : tutoriel : mp-sample.c

Note

Regardez le tutoriel au complet, en Anglais, ici.
Vous trouverez tout ce tutoriel séparé en plusieurs pages ici.
Ce fichier est l’exemple le plus simple pour mettre en oeuvre les fonctions apr_xx
Il vient d’ici.

/**
 * apr tutorial sample code
 * http://dev.ariel-networks.com/apr/
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <apr_general.h>
#include <apr_pools.h>

#define MEM_ALLOC_SIZE		1024

/**
 * exemple de pool mémoire
 * @remark Vérif. des erreurs omise
 */
int main(int argc, const char *argv[])
{
    apr_status_t rv;
    apr_pool_t *mp;
    char *buf1;
    char *buf2;

    /* initialisation par processus (per-process) */
    rv = apr_initialize();
    if (rv != APR_SUCCESS) {
        assert(0);
        return -1;
    }

    /* créer un pool mémoire. */
    apr_pool_create(&mp, NULL);

    /* allouer de la mémoire via le pool */
    buf1 = apr_palloc(mp, MEM_ALLOC_SIZE);
    buf2 = apr_palloc(mp, MEM_ALLOC_SIZE);

    /* détruire le pool mémoire
      (ce qui était alloué au dessus sera
      automatiquement libéré) */
    apr_pool_destroy(mp);

    apr_terminate();
    return 0;
}