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(×pec, 0, sizeof(struct itimerspec));
timespec.it_value.tv_sec = duration;
timer_result = timer_settime(*timer, 0, ×pec, 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.
Related
I have a function void startScanner(...) taking two function pointer as arguments: userType *vConfig(void) and void * vCallback(void). In this function i would like to create a thread and call vCallback() function in the function thread created. So i decided to pass vCallback as args to pthreadcreate.
The code of startScanner function :
void startScanner(tUsrStatus (*vConfig)(), void* (vCallback)()){
if(pthread_create(&scannerThread, NULL, scannerThreadFunc, vCallback))
{
printf("Thread creation fails!\n");
}
}
The scannerTread function:
static void *scannerThreadFunc(void *arg()){
void *funcptr(void) = arg;
while(1)
{
funcptr();
}
pthread_exit(NULL);
}
I get the following error:
error: function ‘funcptr’ is initialized like a variable
error: nested function ‘funcptr’ declared but never defined
How can i fix this?
Syntax errors aside (*) , it's impossible in standard C to pass a function pointer in a void *. There's a fundamental difference between pointers to functions and pointers to data, they can't be converted into each other. This is because there might be platforms where function and data pointers would differ even in size, or refer to different address spaces, or whatever.
But of course, there's a simple way to achieve what you want: Put your function pointer inside a struct and pass a pointer to that.
typedef (*callback)(void);
typedef struct threadargs
{
callback cb;
} threadargs;
void mycallback(void)
{
// ...
}
void *threadfunc(void *arg)
{
threadargs *ta = arg;
// call your callback:
ta->cb();
return ta; // or: return 0, or some pthread_exit(), ...
}
int main(void)
{
pthread_t thread;
threadargs ta = { mycallback };
pthread_create(&thread, 0, threadfunc, &ta);
// make sure "ta" lives for as long as the thread executes,
// here just wait until it exits:
pthread_join(&thread, 0);
}
add error checking etc.
(*) as for the concrete error you're getting, a function pointer needs parantheses around the identifier, so instead of
void *funcptr(void) = arg;
you'd have to write
void (*funcptr)(void) = arg;
To facilitate the usage of function pointers, it's common to typedef them, as seen in my example above. Anyways, as explained above, this wouldn't solve your problem here.
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, ¶ms);
if (!ret)
{
ret = pthread_detach(thread);
}
return ret;
}
static void * pin_thread_function(void * context)
{
struct pin_thread_params params;
memcpy(¶ms, 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.
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).
It seems sensible to wrap a call to del_timer() or del_timer_sync() within an if() statement, such as:
if (timer_pending(&t))
{
del_timer_sync(&t);
}
but can I safely do that in the case where we may not yet have done our init_timer() call on struct t? Do I need to jump through hoops doing something like this instead?
init_timer(&t);
t.function = foo;
.
.
.
if (t.function && timer_pending(&t)) ...
I doubt it.
Here's the code (timer.h#L169) for timer_pending:
static inline int timer_pending(const struct timer_list * timer) {
return timer->entry.next != NULL;
}
And here's the code (timer.c#L621) that ends up initializing the timer when you call init_timer:
static void do_init_timer(struct timer_list *timer, unsigned int flags,
const char *name, struct lock_class_key *key)
{
struct tvec_base *base = __raw_get_cpu_var(tvec_bases);
timer->entry.next = NULL;
timer->base = (void *)((unsigned long)base | flags);
timer->slack = -1;
#ifdef CONFIG_TIMER_STATS
timer->start_site = NULL;
timer->start_pid = -1;
memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
lockdep_init_map(&timer->lockdep_map, name, key, 0);
}
Note that timer_pending is checking entry.next which is not initialized until you call init_timer. So timer_pending may return true when the timer has not been initialized.
I don't know what the effect may be of callingn del_timer_sync on a timer which has not been initialized, though.
del_timer() does the timer_pending() check internally, you don't have to.
You must however have called init_timer() before calling del_timer. (After all, if you don't it'll just contain garbage).
So this is enough:
init_timer(&t);
del_timer(&t);
I have a MyLib.h which has
typedef void *MyThread;
and a MyLib.c which has:
typedef struct
{
ucontext_t *context;
int tid;
}_MyThread;
there is a test function that creates a thread and issues a join as:
void f0(void * dummy)
{
MyThread t1;
printf("f0 start\n");
t1 = MyThreadCreate(f1, NULL);
_MyThread *t = (_MyThread*)t1;
printf("passed value=%d\n",t->tid);
printf("f0 join on t1\n");
MyThreadJoin(t1);
....
}
MyThreadCreate and MyThreadJoin in MyLib.c are as follows:
MyThread MyThreadCreate(void(*start_funct)(void *), void *args)
{
_MyThread child_thread;
...
//setting the child thread's tid
child_thread.tid = ++active_threads;
... MyThread ret = (MyThread)&child_thread;
return ret;
}
int MyThreadJoin(MyThread thread)
{
_MyThread *arg_thread;
arg_thread = (_MyThread*)thread;
int id = arg_thread->tid;
....
}
My problem is, when I run the above, I get:
passed value=2
f0 join on t1
arg_thread->tid = 13
The passed value = "2" is correct, however the value "13" that comes up inside the library function is wrong. Why is the passed value dereferenced in the same way coming different from calling function and different in called function?
Can you add code to print out the memory address of arg_thread and t. I have a feeling what is going on is that your pointer is being sliced in half by a cast. Is MyThreadJoin being forward declared in MyLib.h correctly? Are you compiling your code as 64 bit?
[edit]
I just saw your comment where you were creating t. It looks like you are allocating it on the stack,(not the heap). When you go up a stack frame, it's memory hasn't been overwritten. When you push a new function on to the stack, it overwrites the memory on t. The simple solution is to malloc the struct in your construction function.