LINUX.ORG.RU

OpenGL приложение сегфолтится, если удалить данные текстуры

 ,


0

1

Пытаюсь сделать многооконное приложение OpenGL. Для создания окна я заполняю структуру

typedef struct{
	int ID;            // identificator
	char *title;       // title of window
	GLuint Tex;        // texture for image inside window
	int GL_ID;         // identificator of OpenGL window
	GLubyte *rawdata;  // raw image data
	int w; int h;      // image size
	pthread_t glthread;// thread identificator
	pthread_mutex_t mutex;// mutex for operations with image
} windowData;
typedef struct list_{
	windowData *data;
	struct list_ *next;
	struct list_ *prev;
} WinList;
здесь rawdata — "сырые" данные, которые будут отображаться в текстуре на окне (видео, изображения и т.п.).

Все это инициализируется успешно, открывается и работает. Но как только я открываю 2 окна и пытаюсь закрыть одно из них, происходит сегфолт.

Закрываю так:

int destroyWindow(int window, winIdType type){
	windowData *win;
	if(type == OPENGL)
		win = searchWindow_byGLID(window);
	else
		win = searchWindow(window);
	if(!win) return 0;
	pthread_mutex_lock(&win->mutex);
	glDeleteTextures(1, &win->Tex);
	glFinish();
	glutDestroyWindow(win->GL_ID);
	win->GL_ID = 0; // reset for forEachWindow()
	pthread_mutex_unlock(&win->mutex);
	//removeWindow(win->ID);
	totWindows--;
	return 1;
}
Если закомментировать (как в этом коде) строчку removeWindow(win->ID);, то сегфолт не происходит. Однако, если ее раскомментировать, то приложение падает.

Вот функция removeWindow:

int removeWindow(int winID){
	WinList *node = searchWindowList(winID);
	if(!node) return 0;
	WinList_freeNode(&node);
	return 1;
}
Она просто ищет узел в списке и вырезает его:
void WinList_freeNode(WinList **node){
	if(!node || !*node) return;
	WinList *cur = *node;
	windowData *win = cur->data;
	FREE(win->title);
	FREE(win->rawdata); // *
	pthread_mutex_destroy(&win->mutex);
	if(cur->prev)
		cur->prev->next = cur->next;
	if(cur->next)
		cur->next->prev = cur->prev;
	FREE(*node); // *
}
Если в последней функции закомментировать обе отмеченные звездочкой строки, ничего не падает; но стоит хоть одну раскомментировать, опять сегфолт. Я вообще не понимаю, почему это происходит!

Что здесь может быть не так? Как правильно освободить память, использующуюся OpenGL'ем?


Итак, во всем были виноваты мои кривые руки.


Дополнил сниппеты

☆☆☆☆☆

Последнее исправление: Eddy_Em (всего исправлений: 1)

Если закомментировать, то сегфолта нет, если раскомментировать - есть

Интересный воркфлоу, но все же, почему бы дебаггером не посмотреть стектрейс?

Midael ★★★★★
()
Ответ на: комментарий от Eddy_Em

Плохо. Я наверное сишечку недостаточно хорошо знаю, но сильное подозрение что падает не на вызовах FREE (еще неизвестно что это за макрос), а где-то позднее при попытке к освобожденным участкам обратиться.

А чтобы понять надо либо дебаггером смотреть какой вызов приводит к SIGSEGV, либо как ниже написали

Midael ★★★★★
()
Последнее исправление: Midael (всего исправлений: 1)
Ответ на: комментарий от Eddy_Em

Бери валгринд и херач через него - покажет весь трейс какая рутина какую дергала и где что пошло не так, напишет англицким по черному.

deep-purple ★★★★★
()
Ответ на: комментарий от Eddy_Em

не умеешь - учись. не хочешь - не пиши код.

anonymous
()
Ответ на: комментарий от Midael

Во всем оказались виноваты мои корявые руки:

void* change_image(void *data){
	FNAME();
	windowData *win = (windowData*) data;
	int w = win->w, h = win->h, x,y;
	GLubyte i;
	DBG("w=%d, h=%d",w,h);
	for(i = 1; ;i++){
		GLubyte *raw = win->rawdata;
		pthread_mutex_lock(&win->mutex);
		for(y = 0; y < h; y++){
			if(y%20 == 19){
				raw += w*3;
				continue;
			}
			for(x = 0; x < w; x++){
				if(x%20 != 19){
					if(i < 80) raw[0]++;
					else if(i < 170) raw[1]++;
					else raw[2]++;
				}
				raw += 3;
			}
		}
		pthread_mutex_unlock(&win->mutex);
		usleep(10000);
	}
}
Переписал функцию:
int destroyWindow(int window, winIdType type){
	windowData *win;
	if(type == OPENGL)
		win = searchWindow_byGLID(window);
	else
		win = searchWindow(window);
	if(!win) return 0;
	pthread_mutex_lock(&win->mutex);
	if(!pthread_cancel(win->thread)){ // cancel thread changing data
		WARN(_("can't cancel a thread!"));
	}
	glDeleteTextures(1, &win->Tex);
	glFinish();
	glutDestroyWindow(win->GL_ID);
	win->GL_ID = 0; // reset for forEachWindow()
	pthread_mutex_unlock(&win->mutex);
	removeWindow(win->ID);
	totWindows--;
	return 1;
}
Теперь если убить второе окно, то все ОК. Если убить первое, то падает. Буду дальше искать, где глюк. Наверняка, дыра какая-то в реализации связанных списков.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Shadow1251
#define FREE(ptr) do{free(ptr); ptr = NULL;}while(0)
Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Теперь если убить второе окно, то все ОК. Если убить первое, то падает. Буду дальше искать, где глюк. Наверняка, дыра какая-то в реализации связанных списков.

if(cur->next) cur->next->prev = cur->prev;

У первого же окна нет prev?

Midael ★★★★★
()
Ответ на: комментарий от Midael

В общем, рукожопие победило!

Оно там NULL, все ОК.

Нашел косяк: я когда удалял элемент, совсем забыл про корневой (т.е. если он удаляется, надо обновлять):

void WinList_freeNode(WinList **node){
	if(!node || !*node) return;
	WinList *cur = *node, *prev = cur->prev, *next = cur->next;
	windowData *win = cur->data;
	if(root == cur) root = next; // вот эта строчечка у меня отсутствовала!
	FREE(win->title);
	FREE(win->rawdata);
	pthread_mutex_destroy(&win->mutex);
	FREE(*node);
	if(prev)
		prev->next = next;
	if(next)
		next->prev = prev;
}

Теперь в любом порядке окна удаляются.

// Это я "сниппет" писал для будущего использования, а то часто нужно картинки отображать на экране, и приходилось постоянно что-то велосипедить. Теперь будет отдельный модуль, который легко включить в основной код.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от anonymous

Еще я культи не использовал! Кроме того, я не знаю С++ и знать не хочу эту гадость!

До этого делал на говнотыке, но это дерьмо мне тоже нафиг не нужно. А вот напрямую на GLUT — замечательно.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от makoven

Что-то было, вроде cgl. Но я не щупал за ненадобностью. Если потребуется всякое говно рисовать (вроде полей ввода, кнопочек и прочей гадости), то буду использовать.

Eddy_Em ☆☆☆☆☆
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.