hello morris

Attachment: compile_app2
Description: Binary data

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <mpfr.h>
#include <string.h>
#include <gtk/gtk.h>
#include <sys/time.h>
#include <errno.h>

/* build with:

gcc threaded_app.c -o threaded_app -Wall -pedantic -std=gnu99 -lgmp -lmpfr -pthread -D_REENTRANT -ggdb `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`

*/

typedef struct
{
    struct timeval tv_start;
    struct timeval tv_end;
} Timer;

void timer_start(Timer* t)
{
    gettimeofday(&t->tv_start, 0);
}

void timer_stop(Timer* t)
{
    gettimeofday(&t->tv_end, 0);
}

long timer_get_elapsed(Timer* t)
{
    if (t->tv_start.tv_sec == t->tv_end.tv_sec)
        return t->tv_end.tv_usec - t->tv_start.tv_usec;
    else
        return (t->tv_end.tv_sec - t->tv_start.tv_sec) *
            1e6 + (t->tv_end.tv_usec - t->tv_start.tv_usec);
}

#define NTHREADS 8

#define IMG_WIDTH  480
#define IMG_HEIGHT 360

#if (G_BYTE_ORDER == G_BIG_ENDIAN)
#   define RGB(r,g,b) ((r) << 24 | ((g) << 16) | ((b) << 8))
#   define RED(x)     (((x) & 0xff000000) >> 24)
#   define GREEN(x)   (((x) & 0x00ff0000) >> 16)
#   define BLUE(x)    (((x) & 0x0000ff00) >> 8)
#elif (G_BYTE_ORDER == G_LITTLE_ENDIAN)
#   define RGB(r,g,b) ((r) | ((g) << 8) | ((b) << 16))
#   define RED(x)     ((x) & 0x000000ff)
#   define GREEN(x)   (((x) & 0x0000ff00) >> 8)
#   define BLUE(x)    (((x) & 0x00ff0000) >> 16)
#else
#   error Your machine has an unsupported byte order. Please send patch :)
#endif

typedef struct
{
    int* arr;
    guint32* rgb_data;

    int next_line;
    int lines_done;
    int rendering;
    int start;
    int stop;
    pthread_t rend[NTHREADS];

    int all_quit;

    int width;
    int height;

    double xmin, xmax, ymax;
    int depth;

    gint gui_idle_id;

    char* lines_rendered;
    char* lines_drawn;

    int min_rendered;
    int min_drawn;

} image_info;


static gboolean delete_event(GtkWidget *widget,
                             GdkEvent  *event,
                             gpointer   data);
static void destroy(GtkWidget *widget, gpointer data);

void gui_start_render(GtkWidget* widget, gpointer data);
void gui_stop_render(GtkWidget* widget, gpointer data);

gint gui_idle_draw_cb(image_info* img);

GtkWidget* gui_pbar = NULL;
GtkWidget* drawing_area;

void *render(void* ptr);
int next_line(image_info* img);

void* watch_render_start(void* ptr);
void* watch_render_stop(void* ptr);
void* watch_render_done(void* ptr);

void* threads_render_create(void* ptr);

pthread_mutex_t next_line_mutex =  PTHREAD_MUTEX_INITIALIZER;
//pthread_mutex_t lines_done_mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t img_start_mutex =      PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t img_stop_mutex =       PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t img_rendering_mutex =  PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t img_start_cond =  PTHREAD_COND_INITIALIZER;
pthread_cond_t img_stop_cond =   PTHREAD_COND_INITIALIZER;
pthread_cond_t img_done_cond =   PTHREAD_COND_INITIALIZER;
pthread_cond_t lines_rendered_cond =  PTHREAD_COND_INITIALIZER;

pthread_mutex_t img_lines_rendered_mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t all_quit_mutex = PTHREAD_MUTEX_INITIALIZER;

int main(int argc, char **argv)
{
    printf("initializing...\n");
    image_info* img = malloc(sizeof(image_info));
    memset(img, 0, sizeof(image_info));

    img->start = 0;

    img->width = IMG_WIDTH;
    img->height = IMG_HEIGHT;

    img->xmin = -2.0;
    img->xmax =  1.5;
    img->ymax =  1.25;
    img->depth = 300;


    img->xmin = -7.6243636067708333333333328e-1;
    img->xmax = -7.6243355758101851851851869e-1;
    img->ymax = 7.7996663411458333333333929e-2;
    img->depth = 30000;


    img->gui_idle_id = -1;

    size_t y_asz = img->height * sizeof(int);
    size_t xy_asz = img->width * y_asz;

    printf("creating array size: %ld bytes\n", xy_asz);
    img->arr = malloc(xy_asz);
    if (!img->arr)
    {
        fprintf(stderr, "image dimension too large!\n");
        free(img);
        exit(-1);
    }
    memset(img->arr, 0, xy_asz);

//    img->lines_rendered = malloc(y_asz);
    img->lines_rendered = malloc(img->height);
    if (!img->lines_rendered)
    {
        fprintf(stderr, "image dimension too large!\n");
        free(img->arr);
        free(img);
        exit(-1);
    }

//    img->lines_drawn = malloc(y_asz);
    img->lines_drawn = malloc(img->height);
    if (!img->lines_drawn)
    {
        fprintf(stderr, "image dimension too large!\n");
        free(img->lines_rendered);
        free(img->arr);
        free(img);
        exit(-1);
    }

    img->rgb_data = g_malloc(img->width * img->height * sizeof(guint32));

    int rc_err;
    pthread_t thread_start;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    printf("creating watch render start thread...\n");

    rc_err = pthread_create(&thread_start, &attr,
                              &watch_render_start, (void*)img);
    if (rc_err)
    {
        fprintf(stderr, "Thread start creation failed: %d\n",
                        rc_err);
        free(img->lines_drawn);
        free(img->lines_rendered);
        free(img->arr);
        free(img);
        exit(-1);
    }

    printf("creating GUI...\n");

    GtkWidget* window;
    GtkWidget* startbutton;
    GtkWidget* stopbutton;
    GtkWidget* vbox;
    GtkWidget* hbox;

    gtk_init(&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",
                      G_CALLBACK (delete_event), NULL);
    g_signal_connect (G_OBJECT (window), "destroy",
                      G_CALLBACK (destroy), NULL);
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER (window), vbox);

    hbox = gtk_hbox_new(FALSE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

    startbutton = gtk_button_new_with_label ("Start render");
    g_signal_connect (G_OBJECT (startbutton), "clicked",
                      G_CALLBACK (gui_start_render), img);
    gtk_box_pack_start(GTK_BOX(hbox), startbutton, TRUE, TRUE, 0);
    stopbutton = gtk_button_new_with_label ("Stop render");
    g_signal_connect (G_OBJECT (stopbutton), "clicked",
                      G_CALLBACK (gui_stop_render), img);
    gtk_box_pack_start(GTK_BOX(hbox), stopbutton, TRUE, TRUE, 0);

    gui_pbar = gtk_progress_bar_new();
    gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(gui_pbar),
                                     GTK_PROGRESS_LEFT_TO_RIGHT);
    gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(gui_pbar), 
                               (gfloat)1.0 ); /* img->real_height); */
    gtk_widget_set_size_request(gui_pbar, 75, 0);
    gtk_box_pack_end(GTK_BOX(hbox), gui_pbar, FALSE, FALSE, 0);

    drawing_area = gtk_drawing_area_new();
/*
    gtk_widget_set_events (drawing_area, GDK_BUTTON_PRESS_MASK
                           | GDK_BUTTON_RELEASE_MASK
                           | GDK_POINTER_MOTION_MASK
                           | GDK_EXPOSURE_MASK);
*/
    gtk_widget_set_size_request(drawing_area, img->width, img->height);

    gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE, TRUE, 0);

/*
    g_signal_connect(GTK_OBJECT(tmp), "button_press_event",
                        G_CALLBACK(button_press_event), NULL);
    g_signal_connect(GTK_OBJECT(tmp), "button_release_event",
                        G_CALLBACK(button_release_event), NULL);
    g_signal_connect(GTK_OBJECT(tmp), "expose_event",
                       G_CALLBACK(expose_event), img);
    g_signal_connect(GTK_OBJECT(tmp), "motion_notify_event",
                       G_CALLBACK(motion_event), NULL);
*/

    gtk_widget_show(startbutton);
    gtk_widget_show(stopbutton);
    gtk_widget_show(drawing_area);
    gtk_widget_show(hbox);
    gtk_widget_show(vbox);
    gtk_widget_show(window);

    printf("starting GUI\n");

    gtk_main ();

    printf("************************\n"
           "GUI shutdown\n"
           "************************\n");

    printf("setting all_quit\n");

    pthread_mutex_lock(&all_quit_mutex);
    img->all_quit = 1;
    pthread_mutex_unlock(&all_quit_mutex);

    printf("signalling watch render start thread to wakeup...\n");

    pthread_mutex_lock(&img_start_mutex);
    pthread_cond_signal(&img_start_cond);
    pthread_mutex_unlock(&img_start_mutex);

    printf("waiting for watch render start thread to quit...\n");

    pthread_join(thread_start, NULL);

    printf("done\n");

    printf("freeing memory\n");

    free(img->lines_drawn);
    free(img->lines_rendered);
    free(img->arr);
    free(img);

    printf("goodbye!\n");

    exit(0);
}

gint gui_idle_draw_cb(image_info* img)
{
    int linesdone;

/*
    timeout.tv_nsec = 500 * 1000;
    timeout.tv_sec = 0;
    nanosleep(&timeout, NULL);
*/
/*
    pthread_mutex_lock(&lines_done_mutex);
    if (pthread_cond_timedwait(&line_done_cond,
                               &lines_done_mutex,
                               &timeout) == ETIMEDOUT)
    {
        //printf("!");
        pthread_mutex_unlock(&lines_done_mutex);
        return TRUE;
    }
*/
    pthread_mutex_lock(&img_lines_rendered_mutex);
    linesdone = img->lines_done;
    pthread_mutex_unlock(&img_lines_rendered_mutex);

    int i;
    int miny = img->min_rendered;
    int maxy = miny + 16;
    if (maxy > img->height)
        maxy = img->height;

    if (miny == linesdone) return TRUE;

    if (maxy > linesdone)
    {
        maxy = linesdone;
    }


    int unrendered = 0;

    if (miny < maxy)
    {

        struct timeval tv;
        struct timespec timeout;

        gettimeofday(&tv, NULL);

        timeout.tv_nsec = tv.tv_usec * 1000 + 500 * 1000;
        timeout.tv_sec = tv.tv_sec;
/*
        if (pthread_mutex_trylock(&img_lines_rendered_mutex) == EBUSY)
            return;
*/
        pthread_mutex_lock(&img_lines_rendered_mutex);
        pthread_cond_timedwait(&lines_rendered_cond,
                                   &img_lines_rendered_mutex,
                                   &timeout);
/*
        if (pthread_cond_timedwait(&lines_rendered_cond,
                                   &img_lines_rendered_mutex,
                                   &timeout) == ETIMEDOUT)
        {
            //printf("!");
            pthread_mutex_unlock(&img_lines_rendered_mutex);
            return TRUE;
        }
*/
        for (i = miny; i < maxy; ++i)
        {
            char r = img->lines_rendered[i];
            if (r == 1)
            {
                img->lines_rendered[i] = 2;
                img->lines_drawn[i] = 1;
                if (!unrendered)
                   img->min_rendered = i;
            }
            else if (!r) unrendered = 1;
        }
        pthread_mutex_unlock(&img_lines_rendered_mutex);
    }

    miny = img->min_drawn;
    maxy = miny + 16;
    if (maxy >= img->height)
        maxy = img->height;

    unrendered = 0;

    int w = img->width;

    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gui_pbar),
        (gfloat)miny / (gfloat)img->height);




    if (maxy > linesdone)
        maxy = linesdone;

    for (i = miny; i < maxy; ++i)
    {
        char d = img->lines_drawn[i];
        if (d == 1)
        {
            img->lines_drawn[i] = 2;
            if (!unrendered)
                img->min_drawn = i;
            int x;

            guint32* rgb = &img->rgb_data[i * w];
            int* data = &img->arr[i * w];
            int c;
            for (x = 0; x < w; ++x)
            {
                c = data[x] % 256;
                rgb[x] = RGB(c, c, c);
            }
            gdk_draw_rgb_32_image(drawing_area->window,
                          drawing_area->style->white_gc,
                          0, i, w, 1,
                          GDK_RGB_DITHER_NONE,
                          (guchar*)
                          ((rgb)),
                          w * 4);
        }
        else if (!d) unrendered = 1;
    }
    if (i >= img->height)
    {
        g_source_remove(img->gui_idle_id);
        img->gui_idle_id = -1;
        gtk_widget_hide(gui_pbar);
        return FALSE;
    }

    return TRUE;
}

void gui_start_render(GtkWidget* widget, gpointer ptr)
{
    image_info* img = (image_info*)ptr;

    img->min_rendered = 0;
    img->min_drawn = 0;

//    printf("************\n"
//           "GUI signalling to start render...\n"
//           "************\n");

    pthread_mutex_lock(&img_start_mutex);
    img->start = 1;
    pthread_cond_signal(&img_start_cond);
    pthread_mutex_unlock(&img_start_mutex);
    if (img->gui_idle_id != -1)
    {
        g_source_remove(img->gui_idle_id);
        img->gui_idle_id = -1;
    }
//    memset(img->lines_drawn, 0, img->height * sizeof(int));
    memset(img->lines_drawn, 0, img->height);
    gtk_widget_show(gui_pbar);
    img->gui_idle_id = g_idle_add((GtkFunction)gui_idle_draw_cb, img);
}

void gui_stop_render(GtkWidget* widget, gpointer ptr)
{
    image_info* img = (image_info*)ptr;

//    printf("************\n"
//           "GUI signalling to stop render...\n"
//           "************\n");

    pthread_mutex_lock(&img_stop_mutex);
    img->stop = 1;
    pthread_mutex_unlock(&img_stop_mutex);
}

void* watch_render_start(void* ptr)
{
    image_info* img = (image_info*)ptr;

    int rc_err;
    pthread_t render_thread;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    int r;

    int quit = 0;

    for(;;)
    {
//        printf("watch_render_start: waiting for img_start_cond\n");
        pthread_mutex_lock(&img_start_mutex);
        if (!img->start)
            pthread_cond_wait(&img_start_cond, &img_start_mutex);
        img->start = 0;
        pthread_mutex_unlock(&img_start_mutex);
//        printf("watch_render_start: recieved img_start_cond\n");

        pthread_mutex_lock(&img_rendering_mutex);
        r = img->rendering;
        pthread_mutex_unlock(&img_rendering_mutex);

//        printf("checking if we are rendering... ");

        if (r)
        {
//            printf("Stopping render...\n");
            pthread_mutex_lock(&img_stop_mutex);
            img->stop = 1;
            pthread_cond_signal(&img_stop_cond);
            pthread_mutex_unlock(&img_stop_mutex);
            pthread_join(render_thread, NULL);
//            printf("render stopped\n");
        }
//        else
//            printf("no\n");

        pthread_mutex_lock(&all_quit_mutex);
        quit = img->all_quit;
        pthread_mutex_unlock(&all_quit_mutex);

        if (quit)
        {
//            printf("exiting watch render start thread\n");
            pthread_exit(0);
        }

//        printf("creating render thread...\n");
        rc_err = pthread_create(&render_thread, &attr,
                                &threads_render_create, (void*)img);
        if (rc_err)
            pthread_exit(0);
    }
}

void* threads_render_create(void* ptr)
{
    Timer timing_info;

//    printf("initializing render thread\n");

    image_info* img = (image_info*)ptr;
    pthread_mutex_lock(&img_lines_rendered_mutex);
//    memset(img->lines_rendered, 0, img->height * sizeof(int));
    memset(img->lines_rendered, 0, img->height);
    img->lines_done = 0;
    pthread_mutex_unlock(&img_lines_rendered_mutex);

    pthread_mutex_lock(&img_rendering_mutex);

    img->rendering = 1;
    pthread_mutex_unlock(&img_rendering_mutex);

    pthread_mutex_lock(&img_stop_mutex);
    img->stop = 0;
    pthread_mutex_unlock(&img_stop_mutex);

    pthread_mutex_lock(&next_line_mutex);
    img->next_line = 0;
    pthread_mutex_unlock(&next_line_mutex);

    int rc_err, i;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    timer_start(&timing_info);

    for (i = 0; i < NTHREADS; ++i)
    {
//        printf("creating renderer thread #%d...\n", i);
        rc_err = pthread_create(&img->rend[i], &attr,
                                &render, (void*)img);
        if (rc_err)
        {
            fprintf(stderr, "\nrender thread #%d creation failed: %d\n",
                            i, rc_err);
            return 0;
        }
    }

    for (i = 0; i < NTHREADS; ++i)
    {
//        printf("joining renderer thread #%d...\n", i);
        pthread_join(img->rend[i], NULL);
    }

    timer_stop(&timing_info);
    printf("render-time %.3fs\n\n",
            timer_get_elapsed(&timing_info) / (double)1e6);

//    printf("all renderer threads finished\n");

    pthread_mutex_lock(&img_stop_mutex);
    img->stop = 0;
    pthread_mutex_unlock(&img_stop_mutex);

    pthread_mutex_lock(&img_rendering_mutex);
    img->rendering = 0;
    pthread_mutex_unlock(&img_rendering_mutex);

//    printf("at end of threads_render_create\n");

/*
    pthread_mutex_lock(&lines_done_mutex);
    if (img->lines_done >= img->height)
        printf("image complete\n");
    else
        printf("image interuppted\n");
    pthread_mutex_unlock(&lines_done_mutex);
*/
    pthread_mutex_lock(&img_start_mutex);
    img->start = 0;
    pthread_mutex_unlock(&img_start_mutex);

//    printf("exiting render thread\n");
    pthread_exit(NULL);
}

void* render(void* ptr)
{
    image_info* img = (image_info*)ptr;
    int quit = 0;
//    printf("starting render..\n");
    while(next_line(img) && !quit)
    {
        pthread_mutex_lock(&img_stop_mutex);
        quit = img->stop;
        pthread_mutex_unlock(&img_stop_mutex);

        pthread_mutex_lock(&all_quit_mutex);
        quit |= img->all_quit;
        pthread_mutex_unlock(&all_quit_mutex);
    }
//    printf("exiting render thread\n");
    pthread_exit(0);
}

int next_line(image_info* img)
{
    int line;

    pthread_mutex_lock(&next_line_mutex);
    line = img->next_line++;
    pthread_mutex_unlock(&next_line_mutex);

    if (line >= img->height)
        return 0;

    int ix, wz;
    int img_width = img->width;
    long double x,y,x2,y2,wre=0,wim=0,wre2=0,wim2=0;
    long double xmin = img->xmin, xmax = img->xmax, ymax = img->ymax;
    long double xdiff = xmax - xmin;
    int depth = img->depth;
    long double c_im = 0, c_re = 0;

    y = ymax - (xdiff / (long double)img_width)
                * (long double)line;
    y2 = y * y;

    ix = 0;

    int mx = 0;

    int* arr = &img->arr[line * img_width];

    while (ix < img_width)
    {
        mx += 64;
        if (mx > img_width)
            mx = img_width;
        for (; ix < mx; ++ix)
        {
            x = ((long double)ix / (long double)img_width) * xdiff + xmin;
            x2 = x * x;
            wre = c_re = x;
            wim = c_im = y;
            wre2 = x2;
            wim2 = y2;
            for (wz = 0; wz < depth; ++wz)
            {
                wim = 2.0 * wre * wim + c_im;
                wre = wre2 - wim2 + c_re;
                wim2 = wim * wim;
                wre2 = wre * wre;
                if (wim2 + wre2 > 4.0F)
                    break;
            }
            if (wz == depth + 1)
                wz = 0;
            *arr++ = wz;
        }
        pthread_mutex_lock(&img_stop_mutex);
        if (img->stop)
        {
            pthread_mutex_unlock(&img_stop_mutex);
            return 0;
        }
        pthread_mutex_unlock(&img_stop_mutex);
    }

//    printf("line %d complete\n", line);

    pthread_mutex_lock(&img_lines_rendered_mutex);
    img->lines_rendered[line] = 1;
    pthread_cond_signal(&lines_rendered_cond);
    img->lines_done++;
    if (img->lines_done == img->height)
    {
        pthread_mutex_unlock(&img_lines_rendered_mutex);
        return 0;
    }
    pthread_mutex_unlock(&img_lines_rendered_mutex);

    return 1;
}

static gboolean delete_event(GtkWidget *widget,
                             GdkEvent  *event,
                             gpointer   data)
{
   return FALSE;
}

static void destroy(GtkWidget *widget, gpointer data)
{
    gtk_main_quit ();
}
_______________________________________________
NetBehaviour mailing list
NetBehaviour@netbehaviour.org
http://www.netbehaviour.org/mailman/listinfo/netbehaviour

Reply via email to