[so] Tema4 (relativ urgent)

Bogdan Harjoc harjoc at gmail.com
Fri Jan 6 08:54:49 EET 2006


Salut,

Disclaimer: s-ar putea sa fi inteles eu gresit ce-ai scris tu pe-aici
(mult si pe alocuri amuzant) sau ce scrie pe net in legatura cu
implementarea aio din glibc.

Pe linux, cel putin, nu exista suport in kernel pentru variantele
asincrone ale functiilor read(), write(), etc (exista ceva dar inca
incomplet din cate mi se pare -- vezi
http://lse.sourceforge.net/io/aio.html unde e si libraria userland cu
wrapper-ele pentru syscall-urile din /usr/src/linux/fs/aio.c).

Pentru a putea rula totusi cod care foloseste functiile aio_XXX, se
emuleaza partea relevanta din standardul POSIX prin thread-uri: cand
apelezi aio_read() se creaza un thread (sau se foloseste unul deja
creat dintr-un pool) care apeleaza functiile 'synchronous' si threadul
initial se blocheaza pana cand read(), write(), etc. se termina si e
instiintat de asta.

Iar, s-ar putea sa nu fie asa, dar mi se pare oarecum de asteptat ca,
tinand cont de cele de mai sus, tu cand dai pthread_kill() la firul
creat de tine -- cu pthread_create() -- semnalul sa nu aiba nici un
efect (sau cel putin nu cel dorit) pentru ca ar trebui sa trimiti
semnalul la thread-ul creat de glibc() si caruia nu-i (prea) poti afla
PID-ul (sau thread_id-ul). Probabil programul ala ar merge pe un SO
care are suport in kernel pentru aio_XXX.

As fi curios sa aflu de ce ai nevoie sa intrerupi tu aio_suspend().
N-am scris inca tema dar pare a fi destul in thread-ul principal din
server un loop de genul

while (nr_cereri_aio > 0 && aio_suspend(...) == 0) {
    idx = cauta_aiocb_terminat();
    trimite_raspuns(cblist[idx]);
    cblist[idx] = NULL;
    ...
}

Daca e nevoie totusi sa intrerupi aio_suspend(), poti probabil sa afli
ce thread trebuie semnalizat, doar ca e posibil -- asa se intampla la
mine -- ca request-ul sa se termine 'pe jumatate', adica sa fi citit
de exemplu doar 40M din fisierul ala si request-ul sa se considere
complet si deci aio_error() sa dea 0 iar aio_return() sa returneze
40M, caz in care aio_suspend() returneaza 0 (cel putin asta se
intampla cand rulez testul de mai jos).


Sper sa fie de folos nuvela de mai sus,
bogdan "da' e vacanta ..." harjoc.


// ----------------------
// gcc -Wall -o tst tst.c -lrt
// ./tst

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <aio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>


void sigusr1_handler(int signum)
{
    printf("signal %d %ld\n", signum, pthread_self());
}

void setup_signal()
{
    struct sigaction sa;

    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = sigusr1_handler;
    sigfillset(&sa.sa_mask);
    assert(! sigaction(SIGUSR1, &sa, NULL));
}

#define BUFSZ(16 * (1 << 20))

void * thr_func(void * arg)
{
    struct aiocb cb;
    const struct aiocb * const cblist [] = { &cb };
    char * buf = (char *)malloc(BUFSZ);
    int fd = (int)arg;
    int ret;

    memset(&cb, 0, sizeof(cb));
    cb.aio_fildes = fd;
    cb.aio_buf = buf;
    cb.aio_nbytes = BUFSZ;
    cb.aio_offset = 0;
    cb.aio_sigevent.sigev_signo= SIGUSR1;
    cb.aio_sigevent.sigev_notify= SIGEV_SIGNAL;

    assert(! aio_read(&cb));

    ret = aio_suspend(cblist, 1, NULL);
    printf("aio_suspend: %d\n", ret);
    if (ret == 0) {
        printf("aio_error:  %d\n", aio_error(&cb));
        printf("aio_return: %d\n", aio_return(&cb));
    }

    return NULL;
}

int main()
{
    int fd = open("/dev/urandom", O_RDONLY);
    pthread_t tid;

    assert(fd != -1);
    setup_signal();
    assert(! pthread_create(&tid, NULL, thr_func, (void *)fd));

    printf("killall -USR1 tst ar trebui sa intrerupa aio_suspend()"
       "care sa returneze 0\n");

    pthread_join(tid, NULL);
    return 0;
}


More information about the so mailing list