Search code examples
cgtk3mmap

Passing an integer stored with mmap to GTK


EDIT

This question ended up being two problems packed into one. Yet, I cannot delete the question. The scope of the original question regarding pointers was solved by @David Ranieri. The mmap/fork/gtk problem will be the scope of a new question and will not be addressed here.


I want to print a value I have stored in memory in a GTK window. The integer must be stored using mmap to be retained during a fork elsewhere in the code. I cannot reference this memory mapped address from GTK without getting a SegFault. Am I doing something wrong here? Is there a better way?

My current strategy:

  • Reserve memory for an int with mmap at *VAL
  • Fork process, one half modifies VAL the other half runs GTK
  • Pass *VAL to app in userdata slot
  • The userdata now called localval in activate()
  • Print the value at address localval by converting from gpointer to int.

MWE (this causes a segfault, run at your own risk):

/*
 * MMAP Variable SegFault
 */

#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <gtk/gtk.h>

static void activate (GtkApplication *app, gpointer *localval) {
    GtkWidget *window;
    // Button Containers
    GtkWidget *button_box_quit;
    // Buttons
    GtkWidget *exit_button;
    // Text
    GtkWidget *text_status;
    
    // Define Window, dynamic size for screen.
    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "test");
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
    
    // Define Button Boxes.
    button_box_quit = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
    
    // Define Exit Button, put it in a box, put box in window
    exit_button = gtk_button_new_with_label ("Exit");
    gtk_container_add(GTK_CONTAINER (button_box_quit), exit_button);
    gtk_container_add(GTK_CONTAINER (window), button_box_quit);

    // Connect signals to buttons
    g_signal_connect_swapped (exit_button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
    
    // Define text status
    char msg[32]={0};
    // The "print" line
    g_snprintf(msg, sizeof msg, "val: %d\n", GPOINTER_TO_INT(*localval));
    text_status = gtk_label_new(msg);
    gtk_container_add(GTK_CONTAINER (button_box_quit), text_status);
    
    //Activate!
    gtk_widget_show_all (window);
}

int main (int argc, char **argv) {
    GtkApplication *app;
    int status;
    
    int *VAL = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    int *ABORT = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    int pid = fork();
    
    if (pid == 0) {
        while(!*ABORT) {
            printf("%d\n", *VAL);
            *VAL = *VAL + 1;
            usleep(1000000);
        }
        exit(0);
    } else {
        app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
        // The passing line
        g_signal_connect (app, "activate", G_CALLBACK (activate), (gpointer *)*VAL);
        status = g_application_run (G_APPLICATION (app), argc, argv);
        g_object_unref (app);
        *ABORT = 1;
    }
    *ABORT = 1;
    return status;
}


In a non-working alternative to this code, I tried changing the print line to:

g_snprintf(msg, sizeof msg, "val: %d\n", &GPOINTER_TO_INT(*localval));

But the compiler thinks I want to use the & as a comparator.


Solution

  • You are passing a dereferenced pointer (a value) to a function expecting a pointer:

    int *VAL = ...;
    ...
    g_signal_connect (app, "activate", G_CALLBACK (activate), (gpointer *)*VAL);
    

    switch to

    g_signal_connect (app, "activate", G_CALLBACK (activate), VAL); // Do not use a wrong cast (void **)
    

    also, gpointer is an alias of void *, using gpointer *data you get a void **data, not what you want, so

    static void activate (GtkApplication *app, gpointer *localval) {
    

    should be

    static void activate (GtkApplication *app, gpointer localval) { // without *
    

    finally, to print the value of the pointer use

    g_snprintf(msg, sizeof msg, "val: %d\n", *(int *)localval);