Changing gtk image at a high speed dynamicallly from a gtk c program causing errors

Hi,
I am developing an application in embedded processor with Gtk3+. So I have 16 images which i use to indicate a boolean array of values ie) if value is 1 ,i will show green color image and if value is 0, red image will be shown. This will be running inside a infinite while loop. So when i get interrupt, i will check the value and change the image accordingly.
For changing the image, firstly i tried with gtk_image_set_from_file() but it started to crash as interrupt was so frequent and then i tried with gtk_image_set_from_pixbuf() but here the crash of application is so early with SEGMENTATION FAULT and sometimes with an error “corrupted size vs. prev_size” and sometimes this error"double free or corruption (fasttop)"

I don’t know from where this segmentation fault is occurring as i didn’t use any malloc() or free() in my code.
So can anyone help me with this or is there any-other methods to change the image inside a code at high speed?

Thank you in advance
Regards,
Nishanth

Gtk3 is not thread-safe so most gtk functions should only be called from the main thread. And if you are calling gtk functions in an interrupt handler, that’s similar to calling from the wrong thread.

Hi @jcrain,
I also tried the same with out using the interrupt handler and by checking the values repeatedly and changing the interrupt instead of interrupt but the problem continues.
Thanks for your time mate

If your program crashes it means there likely is some bug in your code, and without seeing it there is not much one can do.

In industrial automation I often have to show digital I/O status, and I’ve used a bunch of read-only GtkCheckButton with a custom class (i for inputs and o for outputs). Then I can customize the appearance in CSS, e.g. I load at start up this custom CSS fragment:

.i, .o, .um {
  font-size: 75%;
}
.i label, .o label {
  color: inherit;
  padding: 0;
  margin: 0;
}
.i check, .o check {
  -gtk-icon-source: -gtk-scaled(url("assets/led-off.svg"));
  background: none;
  border-width: 0;
  background: none;
  box-shadow: none;
  padding: 0;
  margin: 2px 4px 2px 0;
  transition: none;
  min-width: 18px;
  min-height: 18px;
}
.i check:active, .o check:active {
  -gtk-icon-transform: none;
}
.i check:checked {
  background: none;
  -gtk-icon-source: -gtk-scaled(url("assets/led-green.svg"));
}
.o check:checked {
  -gtk-icon-source: -gtk-scaled(url("assets/led-red.svg"));
}

Hi @ntd,
I have attached my code below,

Here

  1. di_val [16] is the boolean array consisting of values .
  2. dig_ip[16] is my gpio input pin array.
    3.diagnosis.DI_indication[16] is the array of gtk images
    4.di_on[16] is the array of green color images in pixbuf.
    5.di_off[16] is the array of red color images in pixbuf

for(int i=0;i<16;i++)
{
di_val[i]=libsoc_gpio_get_level(dig_ip[i]);
if(di_val[i]==HIGH) { gtk_image_set_from_pixbuf(GTK_IMAGE(diagnosis.DI_indication[i]),di_on[i]); }
else { gtk_image_set_from_pixbuf(GTK_IMAGE(diagnosis.DI_indication[i]),di_off[i]); }
}

while(1)
{
	//for Digital inputs
	for(int i=0;i<16;i++)
	{
		if(di_val[i]!=libsoc_gpio_get_level(dig_ip[i]))
		{
			di_val[i]=libsoc_gpio_get_level(dig_ip[i]);
			if(di_val[i]==HIGH)	{	gtk_image_set_from_pixbuf(GTK_IMAGE(diagnosis.DI_indication[i]),di_on[i]);	  }
			else				{	gtk_image_set_from_pixbuf(GTK_IMAGE(diagnosis.DI_indication[i]),di_off[i]);	  }
		}
	}

Thanks for your time

Hi,
Gtk-e[1;33mWARNINGe[0m **: Allocating size to GtkFixed 0xbab68 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?

This is what the error i am getting while my application gets struck. How to clear this issue?
Thanks and regards,
Nishanth

That warning is probably unrelated to your crash so I wouldn’t focus too much on it. That message should only show up in a debug build of Gtk anyway.

I’m not sure how this while loop fits into your application, but infinite loops like this are not often seen in Gtk applications.

Gtk applications are written around an event loop, which you start by calling a function such as g_application_run(), and which only returns when the application is exiting. The main loop polls for events and calls callback functions in your application to handle the events. The gtk_* functions should only be called from these callback functions, in the main loop thread.

If you have some other thread running, polling GPIOs in the background, since you can’t call gtk_* functions from another thread, you need to pass that information to the main loop thread, using a function like g_idle_add() to ask the main loop to call your callback function to handle the event.

Hi Nishanth,

Could you replace the while loop with a timer? How fast do you need updates? You could also try a frame clock instead of a timer.

An image widget will work but you might get more flexibility with a drawing area widget. Are the pixbufs saved drawings? If they are you could just draw directly to a drawing area.

Eric

/*
    gcc -Wall images1.c -o images1 `pkg-config --cflags --libs gtk+-3.0` -lm

    Tested on Ubuntu18.04 and GTK3.22
*/

#include<gtk/gtk.h>
#include<math.h>

static gint image_index=0;
static GdkPixbuf *pixbuf_green[12];

static gboolean draw_main(GtkWidget *da, cairo_t *cr, gpointer data);
static gboolean draw_images(GtkWidget **widgets);
static void save_green_images();
static void get_green_images();

int main(int argc, char **argv)
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Images");
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 400);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    //Save some png's to file.
    save_green_images();
    //Read the saved png's into an array of pixbufs.
    get_green_images();

    GtkWidget *da=gtk_drawing_area_new();
    gtk_widget_set_hexpand(da, TRUE);
    gtk_widget_set_vexpand(da, TRUE);
    g_signal_connect(da, "draw", G_CALLBACK(draw_main), NULL);

    GtkWidget *image=gtk_image_new_from_pixbuf(pixbuf_green[0]);

    GtkWidget *grid=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid), da, 0, 0, 1, 1);
    gtk_grid_attach(GTK_GRID(grid), image, 1, 0, 1, 1);

    gtk_container_add(GTK_CONTAINER(window), grid);

    gtk_widget_show_all(window);

    GtkWidget *widgets[2]={image, da};
    //Test some different times.
    g_timeout_add(1000, (GSourceFunc)draw_images, widgets);

    gtk_main();

    //Clean up pixbufs.
    gint i=0;
    for(i=0;i<12;i++) g_object_unref(pixbuf_green[i]);

    return 0;  
  }
static gboolean draw_images(GtkWidget **widgets)
  {
    if(image_index>10) image_index=0;
    else image_index++;

    //Update the image widget.
    gtk_image_set_from_pixbuf(GTK_IMAGE(widgets[0]), pixbuf_green[image_index]);
    //Update the drawing area widget.
    gtk_widget_queue_draw(widgets[1]);
    return TRUE;
  }
static gboolean draw_main(GtkWidget *da, cairo_t *cr, gpointer data)
  {
    cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
    cairo_paint(cr);

    gdk_cairo_set_source_pixbuf(cr, pixbuf_green[image_index], 0, 0);
    cairo_paint(cr);

    return FALSE;
  }
static void save_green_images()
  {
    gint i=0;
    gdouble x=0.0;
    gdouble y=-100.0;
    gdouble tick=0;

    //Create a surface. 
    cairo_surface_t *surface=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 400, 400);
    cairo_t *cr=cairo_create(surface);

    cairo_translate(cr, 200.0, 200.0);
    cairo_set_line_width(cr, 6);

    for(i=0;i<12;i++)
      {
        cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
        cairo_paint(cr);
        cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
        cairo_arc(cr, 0.0, 0.0, 100.0, 0.0, 2.0*G_PI);
        cairo_stroke(cr);
        cairo_move_to(cr, 0.0, 0.0);
        cairo_line_to(cr, x, y);
        cairo_stroke(cr);
        gchar *file_name=g_strdup_printf("green%i.png", i+1);
        cairo_surface_write_to_png(surface, file_name);
        g_free(file_name);
        tick-=G_PI/6.0; 
        x=100.0*cos(G_PI/2.0+tick);
        y=-100.0*sin(G_PI/2.0+tick);  
      }

    cairo_destroy(cr);
    cairo_surface_destroy(surface); 
  }
static void get_green_images()
  {
    gint i=0;
    GError *error=NULL;
   
    for(i=0;i<12;i++)
      {
        gchar *file_name=g_strdup_printf("green%i.png", i+1);
        pixbuf_green[i]=gdk_pixbuf_new_from_file(file_name, &error);
        if(error!=NULL)
          {
            g_print("pixbuf load error %s\n", error->message);
            g_error_free(error);
          }
        g_free(file_name);
      }

  }
2 Likes

hello @jcrain, Actually this infinite loop is present inside a thread function so there is no problem with the polling in the main loop.
Is it a bad practice to use gtk functions in a thread other than main thread?
Regards,
Nishanth

The pixbuf’s that i use in my code were created by gdk_pixbuf_new_from_file().
Also i will try the code that you shared and will reply back.
Thanks for your time
Regards,
Nishanth

Getting segmentation fault has nothing to do with memory managers the way you are probably thinking.

If you get segmentation fault more probably it happens that you or you application accessed a memory location which does not belong to your application, eg accessing an Array outside its bounds, moving a pointer to bad location, trying to write in read only memory or using a wrong cast.

It is hard to think what’s wrong without a Code which can be compiled and run.

You really need to debug that code.
Do not write 1000 lines of code and see what happens.

Change your code in small functions and call them all one after another.

Create a variable gint i = 0;
And after every function call do:
g_print( “i = %\n”, I++ );

And see where is the last g_print() call.

You cannot use GTK API from any thread that isn’t the main thread—i.e. the one that called gtk_init()/gtk_main() or g_application-run().

See the relevant documentation in GTK.

Hi @cecashon,
I tried with the example provided and also modified my code with g_timeout_add in my main thread. The function is called in defined intervals but the problem is i could not see any changes in the ui and also i dont have any control on my ui. I think this is because of g_timeout_ add, as my gtk_main is not in polling state. Is my perception right?
Can i use the g_timeout_add in a seperate thread?
Thanks and regards,
Nishanth

The g_timeout_add() is using the main thread in the above code. This is a simple way to go about updating some widgets. The time to copy the test images over in an update is much faster than the screen refresh rate. There should be plenty of time to do this with a single thread.

It looks like you have an extra thread that you need to pass information from to the main thread. Not sure where this extra thread is coming from though. Maybe an external library is creating it’s own message loop? Maybe you have an extra worker thread. Since the gtk_ functions only work from the main thread you would need to pass values back to that thread and then update. How this would work in your program I am unsure of.

This is a comparison with the above program. It uses a thread and a while loop. From there it updates an int which then updates the UI. Another way to go about it but a little more complicated. It might be closer to what you are trying to do.

Eric

/*
    gcc -Wall images2.c -o images2 `pkg-config --cflags --libs gtk+-3.0` -lm

    Tested on Ubuntu18.04 and GTK3.22
*/

#include<gtk/gtk.h>
#include<math.h>

static gint image_index=0;
static GdkPixbuf *pixbuf_green[12];
//A 200x200 image. Three of them side by side.
static gdouble image_size=200.0;
static GThread *thread=NULL;

static gboolean draw_da1(GtkWidget *da, cairo_t *cr, gpointer data);
static gboolean draw_da2(GtkWidget *da, cairo_t *cr, gpointer data);
static gpointer thread_tick(GtkWidget **widgets);
static gboolean update_ui(GtkWidget **widgets);
static void save_green_images();
static void get_green_images();

int main(int argc, char **argv)
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Images");
    gtk_window_set_default_size(GTK_WINDOW(window), (gint)(3.0*image_size), (gint)image_size);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    //Save some png's to file.
    save_green_images();
    //Read the saved png's into an array of pixbufs.
    get_green_images();

    GtkWidget *da1=gtk_drawing_area_new();
    gtk_widget_set_hexpand(da1, TRUE);
    gtk_widget_set_vexpand(da1, TRUE);
    g_signal_connect(da1, "draw", G_CALLBACK(draw_da1), NULL);

    GtkWidget *da2=gtk_drawing_area_new();
    gtk_widget_set_hexpand(da2, TRUE);
    gtk_widget_set_vexpand(da2, TRUE);
    g_signal_connect(da2, "draw", G_CALLBACK(draw_da2), NULL);

    GtkWidget *image=gtk_image_new_from_pixbuf(pixbuf_green[0]);

    GtkWidget *grid=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid), da1, 0, 0, 1, 1);
    gtk_grid_attach(GTK_GRID(grid), image, 1, 0, 1, 1);
    gtk_grid_attach(GTK_GRID(grid), da2, 2, 0, 1, 1);

    gtk_container_add(GTK_CONTAINER(window), grid);

    gtk_widget_show_all(window);

    //Start a worker thread.
    GtkWidget *widgets[3]={image, da1, da2};
    thread=g_thread_new("worker_thread", (GThreadFunc)thread_tick, widgets);

    gtk_main();

    g_thread_unref(thread);
    //Clean up pixbufs.
    gint i=0;
    for(i=0;i<12;i++) g_object_unref(pixbuf_green[i]);

    return 0;  
  }
static gpointer thread_tick(GtkWidget **widgets)
  {
    gint i=0;

    while(1)
      {
        g_print("%i Tick\n", i);
        g_usleep(1000000);
        if(i>10)
          {
            g_atomic_int_set(&image_index, 0);
            i=0;
          }
        else g_atomic_int_set(&image_index, ++i);
        g_idle_add((GSourceFunc)update_ui, widgets);
      }

    return NULL;
  }
static gboolean update_ui(GtkWidget **widgets)
  {
    //Update the image widget.
    gtk_image_set_from_pixbuf(GTK_IMAGE(widgets[0]), pixbuf_green[g_atomic_int_get(&image_index)]);
    //Update the drawing area widget.
    gtk_widget_queue_draw(widgets[1]);
    gtk_widget_queue_draw(widgets[2]);

    return TRUE;
  }
static gboolean draw_da1(GtkWidget *da, cairo_t *cr, gpointer data)
  {
    gint index=g_atomic_int_get(&image_index);

    cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
    cairo_paint(cr);

    gdk_cairo_set_source_pixbuf(cr, pixbuf_green[index], 0, 0);
    cairo_paint(cr);

    cairo_set_source_rgba(cr, 1.0, 0.0, 1.0, 1.0);
    cairo_set_line_width(cr, 12);
    cairo_rectangle(cr, 0.0, 0.0, image_size, image_size);
    cairo_stroke(cr);

    return TRUE;
  }
static gboolean draw_da2(GtkWidget *da, cairo_t *cr, gpointer data)
  {
    gint index=g_atomic_int_get(&image_index);
    gdouble x=(image_size/4.0)*cos(G_PI/2.0-G_PI/6.0*index);
    gdouble y=-(image_size/4.0)*sin(G_PI/2.0-G_PI/6.0*index);

    cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 1.0);
    cairo_paint(cr);

    cairo_translate(cr, image_size/2.0, image_size/2.0);
    cairo_set_line_width(cr, 6);
    cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
    cairo_arc(cr, 0.0, 0.0, image_size/4.0, 0.0, 2.0*G_PI);
    cairo_stroke(cr);
    cairo_move_to(cr, 0.0, 0.0);
    cairo_line_to(cr, x, y);
    cairo_stroke(cr);

    cairo_set_source_rgba(cr, 0.0, 1.0, 1.0, 1.0);
    cairo_set_line_width(cr, 12);
    cairo_rectangle(cr, -image_size/2.0, -image_size/2.0, image_size, image_size);
    cairo_stroke(cr);   

    return TRUE;
  }
static void save_green_images()
  {
    gint i=0;
    gdouble x=0.0;
    gdouble y=-(image_size/4.0);
    gdouble tick=0;

    //Create a surface. 
    cairo_surface_t *surface=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_size, image_size);
    cairo_t *cr=cairo_create(surface);

    cairo_translate(cr, image_size/2.0, image_size/2.0);
    cairo_set_line_width(cr, 6);

    for(i=0;i<12;i++)
      {
        cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
        cairo_paint(cr);
        cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
        cairo_arc(cr, 0.0, 0.0, image_size/4.0, 0.0, 2.0*G_PI);
        cairo_stroke(cr);
        cairo_move_to(cr, 0.0, 0.0);
        cairo_line_to(cr, x, y);
        cairo_stroke(cr);
        gchar *file_name=g_strdup_printf("green%i.png", i+1);
        cairo_surface_write_to_png(surface, file_name);
        g_free(file_name);
        tick-=G_PI/6.0; 
        x=(image_size/4.0)*cos(G_PI/2.0+tick);
        y=-(image_size/4.0)*sin(G_PI/2.0+tick);  
      }

    cairo_destroy(cr);
    cairo_surface_destroy(surface); 
  }
static void get_green_images()
  {
    gint i=0;
    GError *error=NULL;
   
    for(i=0;i<12;i++)
      {
        gchar *file_name=g_strdup_printf("green%i.png", i+1);
        pixbuf_green[i]=gdk_pixbuf_new_from_file(file_name, &error);
        if(error!=NULL)
          {
            g_print("pixbuf load error %s\n", error->message);
            g_error_free(error);
          }
        g_free(file_name);
      }
  }
2 Likes

hi @cecashon
Thank you for the code which made me to have a better understanding over using threads. I tried the above logic with my code and i noticed that upon frequently changing the images, ram memory is increasing gradually. I tracked the ram memory with your code and i could see the same increase in memory which makes the application hang when gets fully loaded. Why is the ram memory increasing when images are being updated?
Thank you and regards,
Nishanth

I ran images1 and images2 with valgrind and it doesn’t show a leak over time. How are you testing for leaks? I did notice that if I just use the drawing area, the FcConfigParseAndLoad cache isn’t loaded so that isn’t reported in valgrind.

The images1.c and images2.c should be OK. If you identify a leak over time I would like to know. Sometimes I have trouble with reference counting and have made my share of pointer mistakes over the years. Get them fixed when you find them.

What does valgrind report with your program?

Eric

Hi @cecashon,
I tried with the g_idle_add function and now my code does not crash even a single time.
But the ram memory is slightly increasing over time as 1mb per 20 minutes. I don’t know why this increase in memory happens and i have shared my code below.

#define CH1_PASS 201 //digital outputs
#define CH1_FAIL 202
#define CH1_DONE 88
#define CH1_READY 89

#define CH2_PASS 42
#define CH2_FAIL 46
#define CH2_DONE 45
#define CH2_READY 39

#define CH1_START 1 //digital inputs
#define CH1_STOP 11
#define CH1_MB1 91
#define CH1_MB2 175
#define CH1_MB3 51
#define CH1_MB4 93
#define CH1_MB5 166
#define CH1_MB6 128

#define CH2_START 50
#define CH2_STOP 15
#define CH2_MB1 12
#define CH2_MB2 43
#define CH2_MB3 53
#define CH2_MB4 36
#define CH2_MB5 52
#define CH2_MB6 55

#include<gtk/gtk.h>
#include"libsoc_gpio.h"
#include"libsoc_debug.h"
#include <gdk-pixbuf/gdk-pixbuf.h>

struct dig_input
{
GtkWidget *image;
GdkPixbuf *buf;
}di;

GtkWidget *mainWindow;
GtkBuilder *builder;
GtkWidget *fixed;
GtkWidget *DO_switch[8];
GtkWidget *DI_indication[16];
GdkPixbuf *DI_colourGREEN;
GdkPixbuf *DI_colourRED;
GdkRGBA color;

gpio *do_ch1_p,*do_ch1_f,*do_ch1_d,do_ch1_r; //ch1 Digital output
gpio
di_ch1_s, *di_ch1_st, *di_ch1_mb1, *di_ch1_mb2,*di_ch1_mb3, *di_ch1_mb4,*di_ch1_mb5,*di_ch1_mb6; //ch1 Digital input

gpio *do_ch2_p,*do_ch2_f,*do_ch2_d,*do_ch2_r; //ch2 Digital output
gpio *di_ch2_s,*di_ch2_st,*di_ch2_mb1,*di_ch2_mb2,*di_ch2_mb3, *di_ch2_mb4,*di_ch2_mb5,*di_ch2_mb6; //ch2 Digital input

void diagnosis_screen_init(); //screen widget init
void *diag_loop(void *dummy); //thread while loop
void update_uii(void *digg); //to update image
void DIO_init(); //gpio pins init

int main(int argc, char* argv)
{
pthread_t thread;
GError *error=NULL;
gtk_init(&argc,&argv);
builder = gtk_builder_new();
int f=gtk_builder_add_from_file(builder, “/home/root/diag.ui”, &error);
if (f == 0)
{
g_printerr(“Error loading file: %s\n”, error->message);
g_clear_error(&error);
return 0;
}
diagnosis_screen_init();
DIO_init();

mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(mainWindow,1024, 600);
gtk_window_set_position(GTK_WINDOW(mainWindow),GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_resizable(GTK_WINDOW(mainWindow), false);
gtk_window_set_decorated(GTK_WINDOW(mainWindow), false);
gtk_container_add(GTK_CONTAINER(mainWindow),fixed);
gdk_rgba_parse(&color, “#171515”);
gtk_widget_override_background_color(mainWindow, GTK_STATE_FLAG_NORMAL,&color);
gtk_widget_show_all(mainWindow);
pthread_create(&thread,NULL,diag_loop,NULL);
gtk_main();
return 0;
}
void DIO_init() //input and output pin initializations
{

//Digital outputs
do_ch1_p=libsoc_gpio_request(CH1_PASS,LS_GPIO_SHARED); //for ch1
do_ch1_f=libsoc_gpio_request(CH1_FAIL,LS_GPIO_SHARED);
do_ch1_d=libsoc_gpio_request(CH1_DONE,LS_GPIO_SHARED);
do_ch1_r=libsoc_gpio_request(CH1_READY,LS_GPIO_SHARED);

do_ch2_p=libsoc_gpio_request(CH2_PASS,LS_GPIO_SHARED); //for ch2
do_ch2_f=libsoc_gpio_request(CH2_FAIL,LS_GPIO_SHARED);
do_ch2_d=libsoc_gpio_request(CH2_DONE,LS_GPIO_SHARED);
do_ch2_r=libsoc_gpio_request(CH2_READY,LS_GPIO_SHARED);

if (do_ch1_p == NULL || do_ch1_f == NULL || do_ch1_d == NULL || do_ch1_r == NULL || do_ch2_p == NULL || do_ch2_f == NULL || do_ch2_d == NULL || do_ch2_r == NULL)
{
printf(“error while gpio set request for DO\n”);
return;
}

libsoc_gpio_set_direction(do_ch1_p,OUTPUT); //to set direction as o/p
libsoc_gpio_set_direction(do_ch1_f,OUTPUT);
libsoc_gpio_set_direction(do_ch1_d,OUTPUT);
libsoc_gpio_set_direction(do_ch1_r,OUTPUT);

libsoc_gpio_set_direction(do_ch2_p,OUTPUT);
libsoc_gpio_set_direction(do_ch2_f,OUTPUT);
libsoc_gpio_set_direction(do_ch2_d,OUTPUT);
libsoc_gpio_set_direction(do_ch2_r,OUTPUT);

//Digital inputs
di_ch1_s=libsoc_gpio_request(CH1_START,LS_GPIO_SHARED); //for ch1
di_ch1_st=libsoc_gpio_request(CH1_STOP,LS_GPIO_SHARED);
di_ch1_mb1=libsoc_gpio_request(CH1_MB1,LS_GPIO_SHARED);
di_ch1_mb2=libsoc_gpio_request(CH1_MB2,LS_GPIO_SHARED);
di_ch1_mb3=libsoc_gpio_request(CH1_MB3,LS_GPIO_SHARED);
di_ch1_mb4=libsoc_gpio_request(CH1_MB4,LS_GPIO_SHARED);
di_ch1_mb5=libsoc_gpio_request(CH1_MB5,LS_GPIO_SHARED);
di_ch1_mb6=libsoc_gpio_request(CH1_MB6,LS_GPIO_SHARED);

if(di_ch1_s==NULL || di_ch1_st==NULL || di_ch1_mb1==NULL || di_ch1_mb2==NULL || di_ch1_mb3==NULL || di_ch1_mb4==NULL || di_ch1_mb5==NULL || di_ch1_mb6==NULL)
{
printf(“error while setting digital inputs for ch1\n”);
return;
}

libsoc_gpio_set_direction(di_ch1_s,INPUT);
libsoc_gpio_set_direction(di_ch1_st,INPUT);
libsoc_gpio_set_direction(di_ch1_mb1,INPUT);
libsoc_gpio_set_direction(di_ch1_mb2,INPUT);
libsoc_gpio_set_direction(di_ch1_mb3,INPUT);
libsoc_gpio_set_direction(di_ch1_mb4,INPUT);
libsoc_gpio_set_direction(di_ch1_mb5,INPUT);
libsoc_gpio_set_direction(di_ch1_mb6,INPUT);

libsoc_gpio_set_edge(di_ch1_s, BOTH);			
libsoc_gpio_set_edge(di_ch1_st, BOTH);
libsoc_gpio_set_edge(di_ch1_mb1, BOTH);
libsoc_gpio_set_edge(di_ch1_mb2, BOTH);
libsoc_gpio_set_edge(di_ch1_mb3, BOTH);
libsoc_gpio_set_edge(di_ch1_mb4, BOTH);
libsoc_gpio_set_edge(di_ch1_mb5, BOTH);
libsoc_gpio_set_edge(di_ch1_mb6, BOTH);

di_ch2_s=libsoc_gpio_request(CH2_START,LS_GPIO_SHARED); //for ch2
di_ch2_st=libsoc_gpio_request(CH2_STOP,LS_GPIO_SHARED);
di_ch2_mb1=libsoc_gpio_request(CH2_MB1,LS_GPIO_SHARED);
di_ch2_mb2=libsoc_gpio_request(CH2_MB2,LS_GPIO_SHARED);
di_ch2_mb3=libsoc_gpio_request(CH2_MB3,LS_GPIO_SHARED);
di_ch2_mb4=libsoc_gpio_request(CH2_MB4,LS_GPIO_SHARED);
di_ch2_mb5=libsoc_gpio_request(CH2_MB5,LS_GPIO_SHARED);
di_ch2_mb6=libsoc_gpio_request(CH2_MB6,LS_GPIO_SHARED);

if(di_ch2_s==NULL || di_ch2_st==NULL || di_ch2_mb1==NULL || di_ch2_mb2==NULL || di_ch2_mb3==NULL || di_ch2_mb4==NULL || di_ch2_mb5==NULL || di_ch2_mb6==NULL)
{
printf(“error while setting digital inputs for ch2\n”);
return;
}

libsoc_gpio_set_direction(di_ch2_s,INPUT); //to set direction as i/p for ch2
libsoc_gpio_set_direction(di_ch2_st,INPUT);
libsoc_gpio_set_direction(di_ch2_mb1,INPUT);
libsoc_gpio_set_direction(di_ch2_mb2,INPUT);
libsoc_gpio_set_direction(di_ch2_mb3,INPUT);
libsoc_gpio_set_direction(di_ch2_mb4,INPUT);
libsoc_gpio_set_direction(di_ch2_mb5,INPUT);
libsoc_gpio_set_direction(di_ch2_mb6,INPUT);

libsoc_gpio_set_edge(di_ch2_s, BOTH);			//to set interrupt edge for ch2
libsoc_gpio_set_edge(di_ch2_st, BOTH);
libsoc_gpio_set_edge(di_ch2_mb1, BOTH);
libsoc_gpio_set_edge(di_ch2_mb2, BOTH);
libsoc_gpio_set_edge(di_ch2_mb3, BOTH);
libsoc_gpio_set_edge(di_ch2_mb4, BOTH);
libsoc_gpio_set_edge(di_ch2_mb5, BOTH);
libsoc_gpio_set_edge(di_ch2_mb6, BOTH);

}

void diagnosis_screen_init() //initialization of this screen widgets
{
char indication[16][16]={“DI1_indication”,“DI2_indication”,“DI3_indication”,“DI4_indication”,“DI5_indication”,“DI6_indication”,“DI7_indication”,“DI8_indication”,“DI9_indication”,“DI10_indication”,“DI11_indication”,“DI12_indication”,“DI13_indication”,“DI14_indication”,“DI15_indication”,“DI16_indication”};
char DOswitch[8][11]={“DO1_switch”,“DO2_switch”,“DO3_switch”,“DO4_switch”,“DO5_switch”,“DO6_switch”,“DO7_switch”,“DO8_switch”};

fixed = GTK_WIDGET(gtk_builder_get_object(builder, “diagnosis_screen_fixed”));

for(int i=0;i<16;i++)
{
if(i<8)
{
DO_switch[i]=GTK_WIDGET(gtk_builder_get_object(builder, DOswitch[i])); //for dig. output
}
DI_indication[i] = GTK_WIDGET(gtk_builder_get_object(builder,indication[i])); //for dig. input
}
DI_colourGREEN=gdk_pixbuf_new_from_file(“/home/root/Project/green_btn.png”,NULL);
DI_colourRED=gdk_pixbuf_new_from_file(“/home/root/Project/red_btn.png”,NULL);
}

void *diag_loop(void *dummy)
{
bool do_val[8],di_val[16];
gpio *dig_op[8],*dig_ip[16];
dig_op[0]=do_ch1_p; dig_op[1]=do_ch1_f; dig_op[2]=do_ch1_d; dig_op[3]=do_ch1_r;
dig_op[4]=do_ch2_p; dig_op[5]=do_ch2_f; dig_op[6]=do_ch2_d; dig_op[7]=do_ch2_r;

dig_ip[0]=di_ch1_s; dig_ip[1]=di_ch1_st; dig_ip[2]=di_ch1_mb1; dig_ip[3]=di_ch1_mb2; dig_ip[4]=di_ch1_mb3; dig_ip[5]=di_ch1_mb4; dig_ip[6]=di_ch1_mb5; dig_ip[7]=di_ch1_mb6;
dig_ip[8]=di_ch2_s; dig_ip[9]=di_ch2_st; dig_ip[10]=di_ch2_mb1; dig_ip[11]=di_ch2_mb2; dig_ip[12]=di_ch2_mb3; dig_ip[13]=di_ch2_mb4; dig_ip[14]=di_ch2_mb5; dig_ip[15]=di_ch2_mb6;

struct dig_input di[16];
di[0].image=DI_indication[0];
di[1].image=DI_indication[1];
di[2].image=DI_indication[2];
di[3].image=DI_indication[3];
di[4].image=DI_indication[4];
di[5].image=DI_indication[5];
di[6].image=DI_indication[6];
di[7].image=DI_indication[7];
di[8].image=DI_indication[8];
di[9].image=DI_indication[9];
di[10].image=DI_indication[10];
di[11].image=DI_indication[11];
di[12].image=DI_indication[12];
di[13].image=DI_indication[13];
di[14].image=DI_indication[14];
di[15].image=DI_indication[15];

for(int i=0;i<16;i++)
{
if(i<8)
{
do_val[i]=gtk_switch_get_active(GTK_SWITCH(DO_switch[i]));
if(do_val[i]==0) { libsoc_gpio_set_level(dig_op[i],LOW); }
else { libsoc_gpio_set_level(dig_op[i],HIGH); }
}
di_val[i]=libsoc_gpio_get_level(dig_ip[i]);
if(di_val[i]==HIGH) { gtk_image_set_from_pixbuf(GTK_IMAGE(DI_indication[i]),DI_colourGREEN); }
else { gtk_image_set_from_pixbuf(GTK_IMAGE(DI_indication[i]),DI_colourRED); }
}

while(1)
{
//for Digital output
usleep(1000);
for(int i=0;i<16;i++)
{
if(i<8)
{
if(do_val[i]!=gtk_switch_get_active(GTK_SWITCH(DO_switch[i])))
{

  			do_val[i]=gtk_switch_get_active(GTK_SWITCH(DO_switch[i]));
  			if(do_val[i]==0)	{	libsoc_gpio_set_level(dig_op[i],LOW);	}
  			else				{	libsoc_gpio_set_level(dig_op[i],HIGH);	}
  		}
  	}
     //for Digital input
  	gpio_level level=libsoc_gpio_get_level(dig_ip[i]);
  	if(di_val[i]!=level)            //if input level changed, set the pixbuf in structure as per level and pass to update function
  	{
  		di_val[i]=level;
  		if(di_val[i]==HIGH)	{	di[i].buf=DI_colourGREEN; }
  		else				{	di[i].buf=DI_colourRED;	  }
  		g_idle_add((GSourceFunc)update_uii,&di[i]);
  	}
  }

}
}
void update_uii(void *digg) //func to change image
{
struct dig_input di_pin=(struct dig_input)digg;
gtk_image_set_from_pixbuf(GTK_IMAGE(di_pin->image),di_pin->buf);
}

Is there anything that I can do to avoid the memory consumption?
Thanks for your time mate
Regards,
Nishanth

I would recommend removing the extra thread. There are gtk_ functions in the thread function and there should not be. Use a g_timeout_add() in it’s place. This will work better than the extra thread and you can use the gtk_ functions where you like.

After replacing the extra thread. Compile your code with gcc -Wall -g -fsanitize=address… Fix anything -Wall might output and then run the program when there are no messages. If the address sanitizer stops the program, time to fix it. If it runs no problem then compile with gcc -Wall -g… and run

valgrind --leak-check=full ./program_name

Check for leaks over time. Run the program for a short time and then run it again for a longer time. If the output numbers are not the same start looking for the leak. Find it and fix it.

Eric

1 Like

Hi @cecashon,
Thank you very much. The issue is resolved by using g_timeout_add in place of extra thread. But when run for long time, i can see that the memory is increasing somewhat like 20MB per 30 minutes in ram. I dont know where this memory leak is from as i cant check with valgrind in my device.
Below i have attached my new code.

bool diag_loop()
{
	#if SERIAL_DEBUG
	printf("diagnosis_screen.cpp:diag_loop(): Entering manual mode loop\n");
	#endif

	static bool di_val[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
	struct dig_input di;

	gpio *dig_op[8],*dig_ip[16];
	dig_op[0]=do_ch1_p;	  dig_op[1]=do_ch1_f;   dig_op[2]=do_ch1_d;   dig_op[3]=do_ch1_r;
	dig_op[4]=do_ch2_p;	  dig_op[5]=do_ch2_f;	dig_op[6]=do_ch2_d;	  dig_op[7]=do_ch2_r;

	dig_ip[0]=di_ch1_s;	  dig_ip[1]=di_ch1_st;	dig_ip[2]=di_ch1_mb1;   dig_ip[3]=di_ch1_mb2;   dig_ip[4]=di_ch1_mb3;   dig_ip[5]=di_ch1_mb4;   dig_ip[6]=di_ch1_mb5;   dig_ip[7]=di_ch1_mb6;
	dig_ip[8]=di_ch2_s;	  dig_ip[9]=di_ch2_st;	dig_ip[10]=di_ch2_mb1;   dig_ip[11]=di_ch2_mb2;   dig_ip[12]=di_ch2_mb3;   dig_ip[13]=di_ch2_mb4;   dig_ip[14]=di_ch2_mb5;   dig_ip[15]=di_ch2_mb6;

	if(curr_screen!=DIAG_SCREEN)
	{
		#if SERIAL_DEBUG
		printf("diagnosis_screen.cpp:diag_loop(): Exiting manual mode loop\n");
		#endif
		for(int i=0;i<16;i++)
		{
			if(i<8) {  libsoc_gpio_set_level(dig_op[i],LOW);  }
			di_val[i]=0;
			gtk_image_set_from_pixbuf(GTK_IMAGE(diagnosis.DI_indication[i]),diagnosis.DI_colourRED);
		}
		return FALSE;
	}

	for(int i=0;i<16;i++)
	{
		if(i<8)
		{
			if(gtk_switch_get_active(GTK_SWITCH(diagnosis.DO_switch[i]))==FALSE)  {  libsoc_gpio_set_level(dig_op[i],LOW);  }
			else																  {  libsoc_gpio_set_level(dig_op[i],HIGH);  }
		}
		gpio_level level=libsoc_gpio_get_level(dig_ip[i]);
		if(di_val[i]!=level)
		{
			di.image=diagnosis.DI_indication[i];
			di_val[i]=level;
			if(di_val[i]==HIGH)	{	di.buf=diagnosis.DI_colourGREEN;  }
			else				{	di.buf=diagnosis.DI_colourRED;	  }
			update_ui(&di);
     	}
	}
	return TRUE;
}

void update_ui(void *digg)			//to change the image for di
{
	if(curr_screen==DIAG_SCREEN)
	{
		struct dig_input *di_pin=(struct dig_input*)digg;
		gtk_image_set_from_pixbuf(GTK_IMAGE(di_pin->image),di_pin->buf);
	}
}

Regards,
Nishanth

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.