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);
Related
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.
When creating a vfs using the tcl api how do you get the current filesystem in Tcl_Filesystem.pathInFilesystemProc
My code looks something like this:
typedef struct {
FILE* dbFile;
/*...*/
} FSBackend;
void createFS(const char* dbFile)
{
FSBackend* fsback = (FSBackend*)malloc(sizeof(FSBackend));
initDb(fsback,dbFile);
Tcl_Filesystem tfs;
tfs.typeName="Db Fs";
tfs.structureLength = sizeof(Tcl_Filesystem);
tfs.version = TCL_FILESYSTEM_VERSION_1;
tfs.pathInFilesystemProc = inFsProc;
/*...*/
Tcl_FSRegister((void*),tfs);
}
int inFsProc(Tcl_Obj* pathPtr,ClientData* cd)
{
/* How do I get my FSBackend struct here */
FSBackend* bk = /* ? */
int len;
const char* searchPath = Tcl_GetStringFromObj(pathPtr,&len);
char* foundPath = findFileInDb(searchPath,bk);
if (foundPath == 0) {
return -1;
}
cd = buildInternalRep(foundPath,bk);
return TCL_OK;
}
/**
...
*/
int main()
{
createFS("db1.db");
createFS("db2.db");
}
How do I, in inFsProc get back the struct I passed into Tcl_FSRegister?
The Tcl_FSData function says it can get it but I would then need to get a Tcl_Filesystem pointer
That's a weird one. The clientData handle there is not used to specify a mount point, but rather a separate capability of the filesystem type. Tcl's internal use of Tcl_FSRegister doesn't use it at all. The code which is as close as anything to a canonical use of it is the tclvfs package.
https://github.com/tcl-mirror/tclvfs/blob/master/generic/vfs.c#L385 shows us the use:
static void
Vfs_RegisterWithInterp(interp)
Tcl_Interp *interp;
{
ClientData vfsAlreadyRegistered;
/*
* We need to know if the interpreter is deleted, so we can
* remove all interp-specific mounts.
*/
Tcl_SetAssocData(interp, "vfs::inUse", (Tcl_InterpDeleteProc*)
Vfs_UnregisterWithInterp, (ClientData) 1);
/*
* Perform one-off registering of our filesystem if that
* has not happened before.
*/
vfsAlreadyRegistered = Tcl_FSData(&vfsFilesystem);
if (vfsAlreadyRegistered == NULL) {
Tcl_FSRegister((ClientData)1, &vfsFilesystem);
Tcl_CreateExitHandler(VfsExitProc, (ClientData)NULL);
Tcl_CreateThreadExitHandler(VfsThreadExitProc, NULL);
}
}
As you can see, the clientData there is really just being used as a marker so the code knows whether to do one-time initialisation.
To discover what the mount mapping is, you'll need to keep internal structures. You're strongly recommended to make the Tcl_Filesystem structure instance itself be global (or rather static at file scope) in your code.
I have a lot of code that looks like this:
int bufferSize = fooBufferSize(); // hate having to do this; this logic should be in `foo`
char buffer[bufferSize];
foo(buffer);
bar(buffer);
It happens all the time for me. In the wild, I see something similar a lot:
int bufferSize = snprintf(NULL, 0, format, ...); // exact same issue as above
char buffer[bufferSize+1];
sprintf(buffer, format, ...);
Besides the fact that the above are tedious for the user to write, they also probably redo a lot of computations, which is not only inefficient, but it isn't DRY. I know that I could just malloc the buffer within foo, but there's a lot of issues with that: memory fragmentation, remembering to call free, overhead of malloc/free.
char *foo() {
char *buffer = malloc(...);
// process the data in the buffer
return buffer;
}
main() {
char *buffer = foo();
bar(buffer);
}
There are a lot of cases where I probably would use malloc (or a buffer pool) for things that are constantly removed and deleted (e.g. projectile objects in a game). However, the case that comes up a lot for me is that I want to allocate an object on the stack and then dispose of it when my function returns. The issue is that the object is generally allocated in a stack frame further down from the stack frame I want the object to live in. I'd prefer if I could just build on-top of the stack that foo uses. Like, what if I did this instead:
void foo(char **bufferPtr) {
char buffer[...];
// process buffer
*bufferPtr = buffer;
jmp __builtin_return_address(0); // pseudocode to jump to return address
}
main() {
char *buffer = NULL;
foo(&buffer);
bar(buffer);
}
I don't even know the exact syntax to make this approach work, but it is both GCC-specific and extremely hacky. In addition, if the jump isn't understood by the compiler, local variable states might not be restored properly. I guess, what I really want is for foo to behave like a macro, e.g. like this:
#define foo(buffer) \
char buffer[4]; \
strcpy(buffer, "hey");
int main() {
foo(buffer)
bar(buffer);
}
However, I really don't like using macros (terrible error messages, bad IDE support, slippery slope, etc.)
The macro above looks nice, but in my current usecase, I'm building a computation graph (similar to TensorFlow), and some of the node constructors would look really awkward using macros.
typedef struct {
float *data; // buffer to store output data of computation
int order; // number of dimensions
int *dimensions; // e.g. [3,4] for a 3x4 matrix
} Node;
typedef struct {
Node super; // it's still a node, so just pass a ref to this whenever you need a Node*
Node *A;
Node *B;
} MatMulNode;
void printMatrix(const char *name, Node *node) {
assert(node->order == 2);
printf("%s: [%d x %d]\n", name, node->dimensions[0], node->dimensions[1]);
}
// look at all these backslashes
// also, `return -1` might not make sense in the context this macro is used.
#define matmul(node, left, right) \
if (left.order != 2 || right.order != 2) {\
return -1;\
}\
if (left.dimensions[1] != right.dimensions[0]) {\
return -1;\
}\
int dimensions[2];\
dimensions[0] = left.dimensions[0];\
dimensions[1] = right.dimensions[1];\
float data[dimensions[0] * dimensions[1]];\
MatMulNode node = {\
.super = {\
.data = data,\
.order = 2,\
.dimensions = dimensions,\
},\
.A = &left,\
.B = &right,\
};
int main() {
Node A = {
NULL,
2,
(int[]) {1, 2}
};
Node B = {
NULL,
2,
(int[]) {2, 3}
};
matmul(C, A, B);
printMatrix("A", &A);
printMatrix("B", &B);
printMatrix("C", &C.super);
}
I'm honestly surprised by how well this works, but I also hate the fact that I have to use macros for it and refuse to believe that this is the best API I can make which avoids malloc.
I tried using inline functions, but inline is just a suggestion unless I'm using the always_inline attribute (but that's GCC only), and AFAICT, it doesn't seem to work with alloca. I'm not even sure if the below code has defined behavior, or if I'm just getting lucky:
static inline __attribute__((always_inline)) Node *matmul(Node *left, Node *right) {
if (left->order != 2 || right->order != 2) {
return NULL;
}
if (left->dimensions[1] != right->dimensions[0]) {
return NULL;
}
int dimensions[2];
dimensions[0] = left->dimensions[0];
dimensions[1] = right->dimensions[1];
float data[dimensions[0] * dimensions[1]];
MatMulNode node = {
.super = {
.data = data,
.order = 2,
.dimensions = dimensions,
},
.A = left,
.B = right,
};
return &node.super;
}
The final approach I know of is to use continuation-passing style, e.g.
void matmul(Node *A, Node *B, void callback(void *, Node *C), void *context) {
MatMulNode C = ...;
callback(context, &C.super);
}
The obvious tail-call optimization of this approach is nice, and the fact that the stack is obviously preserved would make it much less hacky than things like jmp, but the API that it presents to the user is really ugly. For example, what if I want to do matmul(A, matmul(B, C))? The code I'd have to write is extremely counter-intuitive, especially because I have to pass in a context variable to the callbacks, when they should Ideally just have access to the entire stack and choose whatever variables they need from there.
void callbackABC(void *context, Node *ABC) {
assert(ABC->order == 2);
printf("A(BC) is [%d x %d]\n", ABC->dimensions[0], ABC->dimensions[1]);
}
void callbackBC(void *context, Node *BC) {
Node *A = context;
matmul(A, BC, callbackABC, NULL);
}
int main() {
Node A = {
NULL,
2,
(int[]) {1, 2}
};
Node B = {
NULL,
2,
(int[]) {2, 3}
};
Node C = {
NULL,
2,
(int[]) {3, 4}
};
matmul(&B, &C, callbackBC, &A);
}
Overall, I think that inline functions are the closest thing to what I want, but rather than ask "How do I force a function to always inline?" I figured I'd ask with the full context of what I want to achieve and why none of my solutions work.
I'm not recommending it, but also you may want to take a look at the __attribute__ cleanup(freefunc) feature in gcc. Basically handles cleanup when the associated variable leaves scope.
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).