Files
openairinterface5g/common/utils/T/tracer/view/textlist.c
T
Cedric Roux 4d7440bfcf add more locks in view/textlist.c
no deadlock should be possible as of the current state of
things. When the textlist's lock is set the GUI lock is
never on.

Let's cross fingers that things don't change crazily in
the future...
2016-05-03 16:40:53 +02:00

155 lines
3.8 KiB
C

#include "view.h"
#include "../utils.h"
#include "gui/gui.h"
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
struct textlist {
view common;
gui *g;
widget *w;
int maxsize;
int cursize;
float refresh_rate;
int autoscroll;
pthread_mutex_t lock;
list * volatile to_append;
};
static void _append(struct textlist *this, char *s, int *deleted)
{
if (this->cursize == this->maxsize) {
text_list_del_silent(this->g, this->w, 0);
this->cursize--;
(*deleted)++;
}
text_list_add_silent(this->g, this->w, s, -1, FOREGROUND_COLOR);
this->cursize++;
}
static void *textlist_thread(void *_this)
{
struct textlist *this = _this;
int dirty;
int deleted;
int visible_lines, start_line, number_of_lines;
while (1) {
if (pthread_mutex_lock(&this->lock)) abort();
dirty = this->to_append == NULL ? 0 : 1;
deleted = 0;
while (this->to_append != NULL) {
char *s = this->to_append->data;
this->to_append = list_remove_head(this->to_append);
_append(this, s, &deleted);
free(s);
}
if (dirty) {
text_list_state(this->g, this->w, &visible_lines, &start_line,
&number_of_lines);
if (this->autoscroll)
start_line = number_of_lines - visible_lines;
else
start_line -= deleted;
if (start_line < 0) start_line = 0;
text_list_set_start_line(this->g, this->w, start_line);
/* this call is not necessary, but if things change in text_list... */
widget_dirty(this->g, this->w);
}
if (pthread_mutex_unlock(&this->lock)) abort();
sleepms(1000/this->refresh_rate);
}
return 0;
}
static void clear(view *this)
{
/* TODO */
}
static void append(view *_this, char *s)
{
struct textlist *this = (struct textlist *)_this;
char *dup;
if (pthread_mutex_lock(&this->lock)) abort();
dup = strdup(s); if (dup == NULL) abort();
this->to_append = list_append(this->to_append, dup);
if (pthread_mutex_unlock(&this->lock)) abort();
}
static void scroll(void *private, gui *g,
char *notification, widget *w, void *notification_data)
{
struct textlist *this = private;
int visible_lines;
int start_line;
int number_of_lines;
int new_line;
int inc;
if (pthread_mutex_lock(&this->lock)) abort();
text_list_state(g, w, &visible_lines, &start_line, &number_of_lines);
inc = 10;
if (inc > visible_lines - 2) inc = visible_lines - 2;
if (inc < 1) inc = 1;
if (!strcmp(notification, "scrollup")) inc = -inc;
new_line = start_line + inc;
if (new_line > number_of_lines - visible_lines)
new_line = number_of_lines - visible_lines;
if (new_line < 0) new_line = 0;
text_list_set_start_line(g, w, new_line);
if (new_line + visible_lines < number_of_lines)
this->autoscroll = 0;
else
this->autoscroll = 1;
if (pthread_mutex_unlock(&this->lock)) abort();
}
static void click(void *private, gui *g,
char *notification, widget *w, void *notification_data)
{
struct textlist *this = private;
int *d = notification_data;
int button = d[1];
if (pthread_mutex_lock(&this->lock)) abort();
if (button == 1) this->autoscroll = 1 - this->autoscroll;
if (pthread_mutex_unlock(&this->lock)) abort();
}
view *new_textlist(int maxsize, float refresh_rate, gui *g, widget *w)
{
struct textlist *ret = calloc(1, sizeof(struct textlist));
if (ret == NULL) abort();
ret->common.clear = clear;
ret->common.append = (void (*)(view *, ...))append;
ret->cursize = 0;
ret->maxsize = maxsize;
ret->refresh_rate = refresh_rate;
ret->g = g;
ret->w = w;
ret->autoscroll = 1;
if (pthread_mutex_init(&ret->lock, NULL)) abort();
register_notifier(g, "scrollup", w, scroll, ret);
register_notifier(g, "scrolldown", w, scroll, ret);
register_notifier(g, "click", w, click, ret);
new_thread(textlist_thread, ret);
return (view *)ret;
}