mardi 4 août 2015

Passin a pointer to a pthread function result in losing his structure

I'm trying to start a thread and giving to him a pointer to a structure. But the pointer received by the function isn't correct. I've got a piece of the structure correct but others aren't.

This is the function where the thread is started :

void start_pointer(struct fsm_pointer *pointer) {
    if ( pointer->started != 0 ){
        printf("CRITICAL : A pointer must be started only once");
        return;
    }
    pthread_create(&pointer->thread, NULL, &pointer_loop, (void *)pointer);
    pointer->started = 1;
}

And here the pointer_loop function :

void *pointer_loop(void * _pointer) {
    struct fsm_pointer * pointer = _pointer; // cast void pointer
    struct fsm_context init_context = {
        .event = event,
        .fnct_args = step.args,
    };
    // call pointer structure member => SEGFAULT
    pointer->current_step.fnct(&init_context); 
    return NULL;
}

The structures are defined as bellow :

struct fsm_pointer{
    pthread_t thread;
    pthread_mutex_t mutex_event;
    pthread_cond_t cond_event;
    struct fsm_event input_event;
    struct fsm_step current_step;
    unsigned short started;
};

struct fsm_step{
    void (*fnct)(const struct fsm_context *);
    void * args;
    struct fsm_trans transition;
};

::EDIT::
Here is where the pointer and step structures come to life :

struct fsm_pointer * create_pointer(struct fsm_step first_step)
{
    struct fsm_pointer *pointer = malloc(sizeof(pointer));
    pointer->thread = 0;
    pointer->mutex_event = PTHREAD_MUTEX_INITIALIZER;
    pointer->cond_event = PTHREAD_COND_INITIALIZER;
    pointer->input_event = _NONE_EVENT;
    pointer->current_step = first_step;
    pointer->started = 0;
    return pointer;
}

struct fsm_step create_step(void (*fnct)(const struct fsm_context *), void *args)
{
    struct fsm_step result = {
            .fnct = fnct,
            .args = args,
            .transition = TRANS_ENDPOINT,
    };
    return result;
}

And here is the function which manage it :

void test_new_fsm(){
    struct fsm_step step_0 = create_step(&callback, NULL);
    struct fsm_pointer *fsm = create_pointer(step_0);

    start_pointer(fsm);
    sleep(5);
    pthread_join(fsm->thread, NULL);
    sleep(1);
    free(fsm);
}

And the callback function is just for the test :

void callback(const struct fsm_context *context) {
    printf("Callback : event uid : %d \n", context->event.uid);
}

::/EDIT::

When I use a debugger (gdb) just before the segfault I can see that the pointer's address is correct (the same as before the thread creation) and that the started variable is correctly set to 1. But the fnct pointer is NULL which produce a segfault.

When the exact same code (with correct variable names) as in the pointer_loop one is executed before the thread creation, there isn't any problem.

So, does someone know what happens, or it's just an obvious mistake which is so obvious that more than a day of debugging isn't enough ?

Thanks.

Aucun commentaire:

Enregistrer un commentaire