I'm creating a Linux GUI using GTK3.0 and C and I want to use the same callback for several switches. In order to differentiate the switch that was clicked, I am trying to use the gpointer argument in g_signal_connect, but the callback doesn't seem to receive the right value.
I create the signals this way:
g_signal_connect(led1_switch, "state-set", G_CALLBACK(on_gpio_btn_click), (gpointer)"LED1");
g_signal_connect(led2_switch, "state-set", G_CALLBACK(on_gpio_btn_click), (gpointer)"LED2");
And the callback tries to get the gpointer passed:
static void on_gpio_btn_click(GtkWidget *wid, gpointer ptr)
{
int gpio;
int val = 0;
char *gpio_switch = ptr;
...
But when I debug the application, the ptr pointer has the value 0x1, a wrong memory address.
Shouldn't it point to the memory address where the constant string "LED1" is stored?
what am I doing wrong? How can I share the same callback for several widgets? I have 8 switches to control GPIOs and I would prefer to have one callback for all of them instead of creating eight.
Your function signature is wrong: the 2nd argument is the value of the switch's state, as can be found in the documentation of the "state-set" signal. That's also the reason why the value is 1: that's the actual value of TRUE.
In other words, your callback will like this:
static void on_gpio_btn_click(GtkSwitch *swtch, gboolean state, gpointer ptr)
{
int gpio;
int val = 0;
char *gpio_switch = ptr;
// ...
}
Related
I made a thread thread1 which creates another thread thread2. When I try to pass the value of fd (fd declared inside thread2) using pthread_exit from thread2 to thread1 I get a garbage value in retval. But when I declare fd as a global variable I get correct value in retval. I got an answer that this is because the thread is finished so it can't pass the value. But in case of functions, a local variable's scope is also limited inside the function and they do return values. So why can't a thread do that?
Here is the code that I tried:
void *thread2(void *message)
{
int fd;
void *retval;
fd=open(message,O_RDWR);
printf("message is - %s",(char *)message);
pthread_exit(&fd);
}
void *thread1(void *message)
{
void *retval;
pthread_t *tid2;
tido=malloc(sizeof(pthread_t));
pthread_create(tid2,NULL,thread2,message);
pthread_join(*tid2,&retval);
printf("fd in write is-%d\n",*(int *)retval);
pthread_exit(&retval);
}
Um... your int fd is an automatic variable (which we may assume is on the stack), so is out of scope when thread2() returns, so passing a pointer to fd out of the function is probably going to lead to disappointment.
A function can return the value of an automatic (aka local) variable. What it cannot do is return the address of one (not and work, anyway).
What you could do is construct a struct to pass into thread2(), to carry parameters in and results back.
I am using a TCP server to send a char array. The function send() takes a char *, but, before that, it has to listen and accept a connection. Given that, I want to send the most recent data when an incoming connection is accepted. Previously, I used two threads. One updated the value in the buffer, the other simply waited for connections, then sent data.
I understand that there can be problems with not locking a mutex, but aside from that, would this same scheme work if I passed the char * to a send function, rather than updating it as a global variable?
Some code to demonstrate:
#include <pthread.h>
char buf[BUFLEN];
void *updateBuffer(void *arg) {
while(true) {
getNewData(buf);
}
}
void *sendData(void *arg) {
//Setup socket
while(true) {
newfd = accept(sockfd, (struct sockaddr *)&their_addr, &size);
send(newfd, buf, BUFLEN, 0);
close(newfd);
}
}
This would send the updated values whenever a new connection was established.
I want to try this:
#include <pthread.h>
char buf[BUFLEN];
void *updateBuffer(void *arg) {
while(true) {
getNewData(buf);
}
}
void *sendData(void *arg) {
TCPServer tcpServer;
while(true) {
tcpServer.send(buf);
}
}
Where the function tcpServer.send(char *) is basically the same as sendData() above.
The reason for doing this is so that I can make the TCP server into a class, since I'll need to use the same code elsewhere.
From my understanding, since I am passing the pointer, it's basically the same as when I just call send(), since I also pass a pointer there. The value will continue to update, but the address won't change, so it should work. Please let me know if that is correct. I'm also open to new ways of doing this (without mutex locks, preferably).
Yes, that is the way most of us do a send, pass a pointer to a buffer either void * or char *
I would coded like this:
int sendData(const char * buffer, const int length)
{
Socket newfd;
Int NumOfConnects=0;
while ((newfd=accept(sockfd, (struct sockaddr *)&their_addr, &size)) > 0)
{
// It would be necessary here to lock the buffer with a Mutex
send(newfd, buffer, length, 0);
// Release the Mutex
close(newfd);
NumOfConnects++;
}
// there is an error in the accept
// this could be OK,
// if the main thread has closed the sockfd socket indicating us to quit.
// returns the number of transfers we have done.
return NumOfConnects;
}
One thing to consider about using a pointer to a buffer which is modify in another thread; Could it be that in the middle of a send the buffer changes and the data sent is not accurate.
But that situation you've already noticed as well. Using a Mutex is suggested as you indicated.
//Block.h
#pragma once
class Block
{
public:
CRect pos;
int num;
public:
Block(void);
~Block(void);
};
//view class
public:
Block currentState[5]; // stores the current state of the blocks
void CpuzzleView::OnDraw(CDC* pDC)
{
CpuzzleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
//draw the 4 blocks and put text into them
for(int i=0;i<4;i++)
{
pDC->Rectangle(currentState[i].pos);
// i'm getting an error for this line:
pDC->TextOut(currentState[i].pos.CenterPoint(), currentState[i].num);
}
pDC->TextOut(currentState[i].pos.CenterPoint(), currentState[i].num);
The error says that no instance of overloaded function CDC::TextOutW() matches the argument list . But the prototype for the function is:
CDC::TextOutW(int x, int y, const CString &str )
all i've done is that instead of the 2 points i've directly given the point object returned by CenterPoint() ... shouldn't it work?
That's because you didn't supplied arguments list correctly. Please read compiler error message carefully, it's usually helps to solve the problem.
TextOut(currentState[i].pos.CenterPoint(), currentState[i].num);
In this call you passed CPoint object and int. This is not correct, you need to pass int, int and CString (or const char* and int length).
To fix this you shall do something like this:
CString strState;
strState.Format("%d", currentState[i].num); // Or use atoi()/wtoi() functions
TextOut(currentState[i].pos.CenterPoint().x, currentState[i].pos.CenterPoint().x, strState);
Is there any way to check if the tasklet_init function which initializes a tasklet has failed?
As you would see if you looked at the source (in kernel/softirq.c):
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data)
{
t->next = NULL;
t->state = 0;
atomic_set(&t->count, 0);
t->func = func;
t->data = data;
}
all the function does is set some structure members, so there is no possible way tasklet_init can fail.
In general if a kernel function returns void then you don't need to check if it succeeded or not. And of course the nice thing about the Linux kernel is that you can always refer to the source and see if there are any ways something can fail.
Here is an example of thread creation code that is often seen. pthread_create uses a lot of pointers/addresses and I was wondering why this is so.
pthread_t threads[NUM_THREADS];
long t;
for(t=0; t<NUM_THREADS; t++){
rc = pthread_create(&threads[t], NULL, &someMethod, (void *)t);
}
Is there a major advantage or difference for using the '&' to refer to the variable array 'threads' as well as 'someMethod' (as opposed to just 'threads' and just 'someMethod')? And also, why is 't' usually passed as a void pointer instead of just 't'?
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg);
You need to pass a pointer to a pthread_t variable to pthread_create. &threads[t] and threads+t achieve this. threads[t] does not. pthread_create requires a pointer so it can return a value through it.
someMethod is a suitable expression for the third argument, since it's the address of the function. I think &someMethod is redundantly equivalent, but I'm not sure.
You are casting t to void * in order to jam a long into a void *. I don't think a long is guaranteed to fit in a void *. It's definitely a suboptimal solution even if the guarantee exists. You should be passing a pointer to t (&t, no cast required) for clarity and to ensure compatibility with the expected void *. Don't forget to adjust someMethod accordingly.
pthread_t threads[NUM_THREADS];
long t;
for (t=0; t<NUM_THREADS; t++) {
rc = pthread_create(&threads[t], NULL, someMethod, &t);
}