• # Bout de code

    Posté par . En réponse au message Programmer un outil d'impression.... Évalué à 3.

    Pour 'daemonizer' le processus courant, j'utilise ce bout de code (le boolean en paramètre sert à indiquer si on doit faire un double fork ou pas -- en pratique, si tu le lances pas avec init faut le mettre à true):

    ------------------------------8<--------------------------------

    static void daemonize(int dofork)
    {
    /** @brief This daemonizes the current process */

    pid_t pid;
    struct rlimit limit;

    /* Set to background */
    if (dofork || getppid() != 1)
    {
    pid = fork();

    switch(pid)
    {
    case -1: /* Error */
    perror(ERR(daemonize, fork)); exit(1);
    break;
    case 0: /* Success */
    break;
    default: /* Kill the father */
    exit(0);
    }

    /* Run the processus in a new session */
    setpgid(0, 0);

    pid = fork();

    switch(pid)
    {
    case -1: /* Error */
    perror(ERR(daemonize, fork)); exit(1);
    break;
    case 0: /* Success */
    break;
    default: /* Kill the father */
    exit(0);
    }

    /* Ignore terminal signals */
    if (signal(SIGTTIN, SIG_IGN) == SIG_ERR)
    {
    perror(ERR(daemonize, signal)); exit(1);
    }
    if (signal(SIGTTOU, SIG_IGN) == SIG_ERR)
    {
    perror(ERR(daemonize, signal)); exit(1);
    }
    if (signal(SIGTSTP, SIG_IGN) == SIG_ERR)
    {
    perror(ERR(daemonize, signal)); exit(1);
    }
    if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
    {
    perror(ERR(daemonize, signal)); exit(1);
    }
    }

    /* Change directory to root */
    if (chdir("/") != 0) { perror(ERR(daemonize, chdir)); exit(1); }

    /* Get the maximum file descriptor */
    if(getrlimit(RLIMIT_NOFILE, & limit) == -1)
    {
    perror(ERR(daemonize, getrlimit)); exit(1);
    }

    /* Close all the file descriptors */
    while (limit.rlim_cur --) { close(limit.rlim_cur); }
    }

    ------------------------------8<--------------------------------

    Sinon, pour ta boucle de lecture de fichier, tu pourrais utiliser fread/fwrite, ou mapper le fichier en mémoire, ou encore (dans ton premier post tu compte utiliser un socket) utiliser un socket, et la super fonction sendfile() :)

    Exemples basiques:

    avec fread/frwrite, ça donne ça:

    ------------------------------8<--------------------------------

    unsigned char buffer[BUFSIZ];
    for ( ;; ) {
    fread(buffer, sizeof(char), sizeof(buffer), in);
    if (! feof)
    fwrite(buffer, sizeof(char), sizeof(buffer), fp);
    else
    break;
    }

    ------------------------------8<--------------------------------

    mais c'est un euphémisme de dire que c'est pas optimal :)

    exemple naïf avec mmap():

    ------------------------------8<--------------------------------

    unsigned char *map = NULL;
    int in = 0;
    int lp = 0;
    struct stat infos;
    size_t taille_fichier = 0;

    if ( (in = open(ton_fichier, O_RDONLY)) == -1) {
    perror(ERR(lecture, open)); abort(); /* gestion d'erreur basique :] */
    }

    if ( (lp = open(imprimante, O_WRONLY)) == -1) {
    perror(ERR(lecture, open)); abort(); /* gestion d'erreur basique :] */
    }

    /* récupère la taille du fichier à balancer */
    if (fstat(in, & infos) == -1)
    perror(ERR(lecture, fstat));
    else
    /* on récupère juste la taille, mais on pourrait vérifier
    * que c'est bien un fichier régulier, toussa...
    */
    taille_fichier = infos.st_size;

    /* mappe le fichier en mémoire (gros tableau) */
    if ( (map = mmap(NULL, taille_fichier, PROT_READ, MAP_PRIVATE, in, 0) == MAP_FAILED) {
    perror(ERR(lecture, mmap)); abort();
    }

    /* oh le gros write de bourrin :) */
    write(fd, map, taille_fichier);

    ------------------------------8<--------------------------------

    Et le must, le gros sendfile() de sauvage, ultra pas portable mais si bourrin :)

    ------------------------------8<--------------------------------

    [Coller ici le même code que pour mmap, mais sans ouvrir lp]

    au lieu d'appeler mmap(), et en supposant que tu as un socket connecté à ton imprimante nommé 'bull':

    ssize_t ret = 0;
    if ( (ret = sendfile(bull, in, NULL, taille_fichier)) == -1)
    perror(ERR(lecture, sendfile));
    else
    printf("youpi, sendfile a envoyé %z bytes dans les tuyaux\n", ret);

    ------------------------------8<--------------------------------

    Et là, enjoy, c'est le noyau qui se tape tout le boulot, et en zero-copy s'il vous plaît :)

    * la macro ERR() qui apparait un peu partout c'est un truc maison pour afficher la ligne du code qui foire:

    #define STRINGIFY(x) #x
    #define STR(x) STRINGIFY(x)
    #define ERR(c, f) #c "()::" #f "() @ " __FILE__ ":" STR(__LINE__)

    Voilà voilà :)