How to pass a local struct as parameter to pthread_create? - c

The following function doesn't work. pin_thread_function sometimes receive garbage instead of the struct data. What is wrong? I know that is some basic scope related problem, but I can't explain.
typedef void (*state_callback_t)(int state);
struct pin_thread_params
{
char pin[3 + 1];
state_callback_t callback_onchange;
};
extern int pin_monitor_create(const char * pin,
state_callback_t callback_onchange)
{
int ret;
unsigned long int thread;
struct pin_thread_params params;
//Setup struct
strcpy(params.pin, "123");
params.callback_onchange = callback_onchange;
//Create thread with struc as parameter
ret = pthread_create(&thread, NULL, pin_thread_function, &params);
if (!ret)
{
ret = pthread_detach(thread);
}
return ret;
}
static void * pin_thread_function(void * context)
{
struct pin_thread_params params;
memcpy(&params, context, sizeof(params));
//Sometimes the correct string, most time garbage
printf("Started monitoring %s", params.pin);
}
When params is malloc'ed before pthread_create, everything works fine, like this:
...
struct pin_thread_params * params;
//Setup struct with malloc
params = malloc(sizeof(struct pin_thread_params));
strcpy(params->pin, "123");
params->callback_onchange = callback_onchange;
...

struct pin_thread_params params is statically allocated and the address of it is not safe to use once the scope of it is over (i.e. after pin_monitor_create has returned). It may happen that sometimes the thread execution starts before the pin_monitor_create has exited and you see the valid data in params. However, the dynamically allocated memory is from heap and will be usable until you free it, so you always get valid data in params within pin_thread_function .

I'm not particularly knowledgeable about pthreads (can't just comment quite yet), but you are passing a pointer to stack allocated memory to the thread which will eventually be clobbered by proceeding function calls.

Related

Casting back void pointer gives different address

I'm doing this callback on linux timer, but I don't know why the address changes when it was converted back on the callback function. Code below
typedef void* timer_cb_args;
typedef void (*timer_cb)(timer_cb_args);
struct cb_wrapper
{
timer_cb callback;
timer_cb_args args;
};
void callback_wrapper(union sigval sv)
{
struct cb_wrapper *cb = (struct cb_wrapper*)(sv.sival_ptr);
printf("Casted sival_ptr pointer on Callback wrapper: %p\n\n", cb);
printf("Callback wrapper function pointer: %p\n", cb->callback);
printf("Callback wrapper args pointer: %p\n\n", &cb->args);
cb->callback(cb->args);
}
int timer_start(timer_handle_t *timer_handle,
timer_cb callback,
timer_cb_args args,
guint32 duration)
{
int ret = 0;
timer_t *timer = calloc(1, sizeof(timer_t));
*timer_handle = (timer_handle_t) calloc(1, sizeof(timer_handle_t));
(*timer_handle)->m_timer = timer;
struct sigevent evp;
memset(&evp, 0, sizeof(struct sigevent));
struct cb_wrapper cbargs;
memset(&cbargs, 0, sizeof(struct cb_wrapper));
cbargs.callback = callback;
cbargs.args = args;
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = &callback_wrapper;
evp.sigev_value.sival_ptr = &cbargs;
printf("sival_ptr pointer on call: %p\n", evp.sigev_value.sival_ptr);
printf("Function pointer: %p\n", cbargs.callback);
printf("Args pointer on call: %p\n\n", cbargs.args);
int timer_result;
timer_result = timer_create(CLOCK_REALTIME, &evp, timer);
if (timer_result < 0)
return -1;
struct itimerspec timespec;
memset(&timespec, 0, sizeof(struct itimerspec));
timespec.it_value.tv_sec = duration;
timer_result = timer_settime(*timer, 0, &timespec, NULL);
if (timer_result < 0)
return -1;
return ret;
}
output is:
sival_ptr pointer on call: 0x7ffce75c3950
Function pointer: 0x55f26d13abb4
Args pointer on call: 0x7ffce75c3a00
Callback wrapper.
Casted sival_ptr pointer on Callback wrapper: 0x7ffce75c3950 //OK same
Callback wrapper function pointer: 0x55f26d13abb4 //OK same
Callback wrapper args pointer: 0x7ffce75c3958 //NOK not same as above
The problem is here:
typedef void* timer_cb_args;
typedef void (*timer_cb)(timer_cb_args);
You are hiding pointers behind typedef and the only thing achieved by that is making everyone including yourself confused.
Therefore you write bugs such as this:
evp.sigev_notify_function = &callback_wrapper;
evp.sigev_value.sival_ptr = &cbargs;
callback_wrapper is a function pointer and they have special rules about dereferencing/decay (Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?), so that line works by accident.
cbargs is however just an ordinary void* so
evp.sigev_value.sival_ptr = &cbargs; assigned a void** to a void*. And since evp.sigev_value.sival_ptr is a void*, that's allowed without the compiler giving diagnostic messages.
This is a really subtle bug! I managed to find it in some five minutes here, but it could as well have taken forever. And the root cause is bad typedef practices.
Fix it like this:
typedef void timer_cb (timer_cb_args);
struct cb_wrapper
{
timer_cb* callback;
void* args;
};
...
evp.sigev_notify_function = callback_wrapper;
evp.sigev_value.sival_ptr = cbargs;
And then clean up the rest of the code accordingly, clearing out all pointers hidden behind typedefs.
Also unrelated to this bug, as someone pointed out it isn't a good idea to pass local variables by reference to callbacks. Because once the function setting up the callback is done, that memory is toast. A normal fix when for example passing variables to thread callbacks, is to pass a pointer to dynamic memory. Or alternatively just ensure that the thread creating thread doesn't die/go out of scope before the end of execution, after all other threads are cleaned up.

Static allocation of struct members within another static struct?

I am trying to implement a low-level thread lock without the use of dynamic memory allocation; this code will basically be used on a completely bare-bones kernel.
However, I am running into the problem of receiving a seg fault when I am trying to dereference a member inside this global static struct. My code is as such
My wrapper struct
/** LOCKING STRUCT & FUNCTIONS **/
struct lock {
int free;
struct thread_list* wait_list;
struct thread* current_holder;
};
The nested struct(intended as a linked list sort of deal)
struct thread_list {
struct thread *head;
};
And the member inside this list
struct thread {
void *top; // top of the stack for this thread
void *sp; // current stack pointer for this thread (context)
void (*start_func)(void *);
void *arg;
int state;
int exit_value;
struct thread *join_thread;
struct thread *next_thread;
int id;
};
The method I'm trying to implement is as such
void lock_init (struct lock *lk) {
lk->free = 1; //Set lock as free
struct thread_list waiting = lk->wait_list; //Get waitlist, works fine
waiting->head = NULL; //Set waitlist's head to null, SEGFAULTS HERE
}
I am not super proficient at C, but I can't seem to figure out the correct methodology/syntax to make my code work like this.
struct thread_list waiting = lk->wait_list; //Get waitlist, works fine
waiting->head = NULL; //Set waitlist's head to null, SEGFAULTS HERE
waiting is not a struct pointer but a struct variable . To access member using it you need to use . operator -
waiting.head = NULL;
Or to use -> operator declare it as a struct pointer .

trying to pass function pointer to pthread

I'm trying to create a pthread with arguments for a function pointer, here first is the function that will be called on pthread creation..
void *passenger(void *arguements){
struct arg_struct *args = arguements;
int passenger = args->p;
int from_floor = args->f;
int to_floor = args->t;
void (*enter)(int,int) = args->en;
void (*exit)(int,int) = args->ex;
// wait for the elevator to arrive at our origin floor, then get in
int waiting = 1;
while(waiting){
if(current_floor == from_floor && state == ELEVATOR_OPEN && occupancy==0) {
pthread_mutex_lock(&lock);
enter(passenger, 0);
occupancy++;
waiting=0;
pthread_mutex_unlock(&lock);
}
}
// wait for the elevator at our destination floor, then get out
int riding=1;
while(riding) {
if(current_floor == to_floor && state == ELEVATOR_OPEN){
pthread_mutex_lock(&lock);
exit(passenger, 0);
occupancy--;
riding=0;
pthread_barrier_wait(&barr);
pthread_mutex_unlock(&lock);
}
}
}
and here is the calling function
void passenger_request(int passenger, int from_floor, int to_floor,void (*enter)(int,int), void(*exit)(int,int))
{
pthread_mutex_lock(&passlock);
struct arg_struct args;
args.p = passenger;
args.f = from_floor;
args.t = to_floor;
args.en = *enter;
args.ex = *exit;
pthread_create(&thread, NULL, &passenger, &args);
//pthread_join(thread, NULL);
pthread_mutex_unlock(&passlock);
// wait for the elevator to arrive at our origin floor, then get in
}
The program is seg faulting when it creates multiple passengers on initilization, if I comment out the pthread_create line no crashing occurs. I'm assuming it's an issue with my passing of arguments for the function pointers, but I'm hazy as to what exactly is going on as all these pointers are starting to confuse me. Any help whatsoever would be much appreciated
also the struct declaration..
struct arg_struct{
int p;
int f;
int t;
void *(*ex)(int,int);
void *(*en)(int,int);
};
args.en = *enter;
args.ex = *exit;
enter and exit are function pointers. Don't dereference them but rather pass them straight through via args. That is, you need:
args.en = enter;
args.ex = exit;
(Assuming you have correct defined struct arg_struct which is not shown.
You are passing your new thread a pointer to args, which is defined on the stack of your passenger_request() function. As soon as passenger_request() returns, this memory could be reused, overwritten, or whatever. It is no longer guaranteed to contain what you put in it. Yet your thread still has a pointer to it and may continue to try to use it. This is likely to cause a crash, although it may be intermittent.
Try doing something different with args. If you only need it once, you could make it global. If you need multiple different ones, then allocate it on the heap with malloc:
void passenger_request(int passenger, int from_floor, int to_floor,void (*enter)(int,int), void(*exit)(int,int))
{
pthread_mutex_lock(&passlock);
struct arg_struct *args = malloc(sizeof(struct arg_struct));
args->p = passenger;
args->f = from_floor;
args->t = to_floor;
args->en = enter;
args->ex = exit;
pthread_create(&thread, NULL, &passenger, args);
//pthread_join(thread, NULL);
pthread_mutex_unlock(&passlock);
// wait for the elevator to arrive at our origin floor, then get in
}
Then in passenger() once you're well and truly done with it, free(args).

Running `Function Pointers` Within Running `POSIX` Thread in `C` `Thread Pool`

I'm creating a threadpool in C with pthreads, and while I have an idea of how it works, I have a few questions about the intricacies.
I've created a struct which is supposed to be my representation of a threadpool, containing a list of function pointers to run, we'll call it the work_list. The threadpool struct also holds mutex's(?) and conditions to syncronize access, an int for the number of threads and an array holding the thread id's of each worked thread.The work_list itself holds structs that represent functions to be completed, each instance of those structs holds a void* to a function, a void* for args and a void* to place results. When coded this idea fleshes out like this:
typedef struct threadpool
{
list work_list;
pthread_t* tidArray;
int num_threads;
pthread_mutex_t lock;
pthread_cond_t condition;
} threadpool;
and:
typedef struct fuFunction
{
void* functionCall;
void* functionArgs;
void* returnValue;
list_elem elem;
} fuFunction;
I currently have a thread which initializes the a pool. It takes in a int num_of_threads, and returns a pointer to instance of a threadpool with all the members initialized. The body I've created looks like this:
threadpool * threadpool_init(int num_of_threads)
{
threadpool* retPool = (threadpool*) malloc(sizeof(threadpool));
//Initialize retPool members
int x;
for(x = 0; x < num_of_threads; x++)
{
pthread_t tid;
if( pthread_create(&tid, NULL, thread_start, retPool) != 0)
{
printf("Error creating worker thread\nExting\n");
exit(1);
}
retPool->tidArray[x] = tid;
}
return retPool;
}
The function that each thread runs when started, the worker function, thread_star, looks like this so far:
void *thread_start(void* args)
{
threadpool* argue = (threadpool*) args;
pthread_mutex_lock(&(argue->lock));
while(\* threadpool not shut down*\)
{
if(!list_empty(&argue->work_list))
{
fuFunction* tempFu = list_entry(list_pop_front(&argue->workQ), fuFunction, elem);
\\WHAT TO PUT HERE
}
pthread_cond_wait(&argue->condition, &argue->lock);
}
pthread_mutex_unlock(&(argue->lock));
}
My question is, assuming this code I currently have is right, how would I get the worker threads to run the function in the tempFu that it makes in the worker function? Sorry if this is long or confusing, I find this much easier to explain in conversation. If this is FUBAR, let me know as well.
the struct element signiture "void* functionCall;" is wrong.
use a function pointer instead.
Eg:
typedef struct fuFunction
{
void* (*functionCall)( void* arg);
void* functionArgs;
void* returnValue;
list_elem elem;
} fuFunction;
then put there:
tempfu->returnValue = (*tempfu->functionCall)(tempfu->functionArgs);

Call pthread_create from outside main function

I want to do something like this:
void *do_work_son(void *data)
{
mystruct *d = (mystruct*)data;
while(true)
{
// d->whatever is corrupt
}
}
void start_thread(pthread_t *mt)
{
mystruct data = ...;
pthread_create(&(*mt), NULL, do_work_son, (void *)&data);
}
int main()
{
pthread mt;
start_thread(&mt);
// do more stuff here
pthread_join(mt, NULL);
}
The idea is spawn off some threads and keep doing more work in main... then when done doing more work, wait for the threads to finish.
It compiles fine, but the data struct is corrupted when it gets accessed inside do_work_son. I think this is because the threads are exiting, even though I'm calling join in main. If I move the pthread_{create,join} calls both to start_thread, it works fine, but then my main function is blocked by the while loop. Am I crazy for doing it this way?
I think this is because the threads are exiting,
No, that's because data is an automatic variable in the start_thread() function, which is invalidated when start_thread() returns, so using its address afterwards invokes undefined behavior.
Either malloc()ate some memory for it, or make it static, or whatever. Just make sure it survives the death of start_thread().
The answer is simple: you are passing a reference of a local variable and then leaving the scope. Replace it with data allocated on heap and it would work like a charm
void start_thread(pthread_t *mt)
{
mystruct *data = malloc(sizeof(*data));
...;
pthread_create(mt, NULL, do_work_son, data);
}
EDIT:
About preassignment question:
void start_thread(pthread_t *mt)
{
mystruct local_data = {...};
mystruct *data = malloc(sizeof(*data));
*data = local_data;
...;
pthread_create(mt, NULL, do_work_son, data);
}

Resources