ufabc-bcc / 2019.Q1.SO.BrisaFS

Projeto de Programação - BrisaFS
3 stars 5 forks source link

Ponto de montagem perde atributos ao tratar sinal de interrupção #3

Open mauromascarenhas opened 5 years ago

mauromascarenhas commented 5 years ago

Ao tentar tratar o sinal de interrupção o diretório/ponto de montagem perde os atributos e deixa vários pipes abertos. Há alguma forma de repassar o tratador de sinal ao do fuse?

Código de exemplo:

void sigint_handler(int sig){
    //Do whatever I have to do here...
    exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[]) 
    // Register a handler for signal sent by CTRL+C
    signal(SIGINT, sigint_handler);

    //Do whatever I have to do here...
    return fuse_main(argc, argv, &fuse_apocalypsefs, NULL);
}
francesquini commented 5 years ago

Aqui você vai enfrentar um problema do ovo e da galinha.

Quando você instala o seu tratador o FUSE não instala o tratador dele. Se você não instalar o seu, então seu programa não finaliza como deveria.

Também não adianta fazer (como eu inicialmente havia sugerido), ou seja, salvar o tratador antigo e repassar o sinal já que o antigo não vai nem ter sido instalado.

O problema todo ocorre pois estamos usando a função de preguiçoso chamada fuse_main. A fuse_main chama a fuse_main_real que está no libfuse/lib/helper.c. Esse cara, cria a sessão fuse depois de fazer o parsing de todos os parâmetros. Em seguida (usando a sessão recém criada) instala os tratadores de sinais.

Uma possivel e boa solução seria seguir o que é feito pela função fuse_main_real. Assim você teria a sessão fuse em mãos para chamar a função fuse_session_exit que recebe a sessão como parâmetro. Veja o arquivo lib/fusesignals.c em especial a função exit_handler.

francesquini commented 5 years ago

TL;DR

Copie o código da função fuse_main_real para a sua main e faça as modificações necessárias para guardar a sessão fuse numa variável. Depois troque o tratador de sinal que o fuse tiver instalado (após a chamada fuse_set_signal_handlers e faça o truque que comentei acima:

struct sigaction handler_original, handler_novo;

void sigint_handler(int sig, siginfo_t *w, void *a) {
    printf("Faz o que tem que ser feito\n");
    //restaura tratador antigo
    if (sigaction(SIGINT, &handler_original, NULL) < 0) {
        printf("Erro re-registrando o handler original\n");
        exit(1);
    }
    //relança o sinal
    raise (sig);
}

int main(int argc, char *argv[]) {
    ...
    ...
    handler_novo.sa_sigaction = sigint_handler;
    sigemptyset(&handler_novo.sa_mask);
    handler_novo.sa_flags = SA_SIGINFO;
    if (sigaction(SIGINT, &handler_novo, &handler_original) < 0) {
        printf("Erro registrando o novo handler\n");
        exit(1);
    }
    _
    _
}