From a5338c572975a82b9efbf95755103176ebbb67a8 Mon Sep 17 00:00:00 2001
From: Ludovic Pouzenc <ludovic@pouzenc.fr>
Date: Sun, 8 Sep 2019 01:52:45 +0200
Subject: alarm(1) before SEM_WAIT(...) in worker_(sdl|gl) to avoid edge cases

---
 src/main.c    | 81 +++++++++++++++++++++++++++++++++++++++--------------------
 src/main.h    |  8 ++++++
 src/scene00.c | 11 ++++++++
 src/scene01.c |  9 +++++++
 src/scene02.c | 10 ++++++++
 5 files changed, 92 insertions(+), 27 deletions(-)

(limited to 'src')

diff --git a/src/main.c b/src/main.c
index 0bb2307..7dd18ee 100644
--- a/src/main.c
+++ b/src/main.c
@@ -31,12 +31,7 @@
 #include <errno.h>     // errno
 #include <stdint.h>    // uint32_t
 #include <stdio.h>     // printf()
-
-#ifdef DEBUG
-#define TRACE(hint) printf("%s(): %s\n", __func__, hint)
-#else
-#define TRACE(hint)
-#endif
+#include <signal.h>    // sigaction()
 
 #ifdef DEBUG_SEM
 #define TRACE_SEM(sem,op,hint) printf("%s(): %s(%s) %s\n", __func__, op, #sem, hint)
@@ -86,6 +81,7 @@ int parent();
 int worker_sdl();
 int worker_gl();
 
+static int skip = 0;
 shm_t *shm;
 
 int main() {
@@ -227,14 +223,28 @@ int parent() {
 	return 0;
 }
 
+static void worker_sdl_sighandler(int sig) {
+	TRACE("call");
+	if ( sig == SIGALRM ) {
+		skip = 1;
+		sem_post(&shm->worker_sdl_can_render);
+	}
+}
+
 int worker_sdl() {
 	int lastscene=-1, res;
+	struct sigaction sa;
 	Uint32 sdl_win_flags = 0; //XXX for final version, consider adding SDL_WINDOW_HIDDEN
 	SDL_RendererInfo renderer_info;
 	SDL_Event sdl_ev;
 
 	TRACE("call");
 
+	sa.sa_handler = worker_sdl_sighandler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	if (sigaction(SIGALRM, &sa, NULL) == -1) return 2;
+
 	// Initialize SDL (http://wiki.libsdl.org/SDL_CreateWindowAndRenderer)
 	// Useful snippet : https://gist.github.com/koute/7391344
 	res = SDL_Init(SDL_INIT_VIDEO);
@@ -251,11 +261,13 @@ int worker_sdl() {
 	shm->ge.sdl_target = SDL_CreateTexture(shm->ge.sdl_rndr, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, FBUF_W, FBUF_H);
 	if (shm->ge.sdl_target == NULL) return 9;
 
+
 	while (!shm->done) {
-		//FIXME change for TRYWAIT for event handling (+delay)
+		alarm(1);
 		SEM_WAIT(&shm->worker_sdl_can_render,20);
+		alarm(0);
 
-		if (!shm->paused) {
+		if (!shm->paused && !skip) {
 			// init / free if scene transition
 			if (lastscene != shm->scene) {
 				switch(lastscene) {
@@ -275,15 +287,15 @@ int worker_sdl() {
 				// If scene init fail, skip to the next one
 				if (res) SCENE_NEXT; else lastscene = shm->scene;
 			}
+			// Compute current scene frame (sdl part)
+			switch(shm->scene) {
+				case 0: res = scene00_next_sdl(&shm->ge, &shm->s00e); break;
+				case 1: res = scene01_next_sdl(&shm->ge, &shm->s01e); break;
+				case 2: res = scene02_next_sdl(&shm->ge, &shm->s02e); break;
+			}
+			if (res) SCENE_NEXT;
 		}
-
-		// Compute current scene frame (sdl part)
-		switch(shm->scene) {
-			case 0: res = scene00_next_sdl(&shm->ge, &shm->s00e); break;
-			case 1: res = scene01_next_sdl(&shm->ge, &shm->s01e); break;
-			case 2: res = scene02_next_sdl(&shm->ge, &shm->s02e); break;
-		}
-		if (res) SCENE_NEXT;
+		if (skip) skip = 0;
 
 		// Event handling for the SDL window (debug purposes)
 		while(SDL_PollEvent(&sdl_ev)) {
@@ -313,16 +325,29 @@ int worker_sdl() {
 	return 0;
 }
 
+static void worker_gl_sighandler(int sig) {
+	TRACE("call");
+	if ( sig == SIGALRM ) {
+		skip = 1;
+		sem_post(&shm->worker_gl_can_render);
+	}
+}
+
 int worker_gl() {
 	int lastscene=-1, res;
+	struct sigaction sa;
 	Uint32 sdl_win_flags = SDL_WINDOW_OPENGL; //XXX for final version, consider adding SDL_WINDOW_HIDDEN
 	SDL_RendererInfo renderer_info;
 	SDL_Event gl_ev;
 
 	TRACE("call");
 
-	// Initialize SDL (http://wiki.libsdl.org/SDL_CreateWindowAndRenderer)
-	// Useful snippet : https://gist.github.com/koute/7391344
+	sa.sa_handler = worker_gl_sighandler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	if (sigaction(SIGALRM, &sa, NULL) == -1) return 2;
+
+	// Initialize SDL for GL. Useful snippet : https://gist.github.com/koute/7391344
 	res = SDL_Init(SDL_INIT_VIDEO);
 	if (res == -1) return 3;
 	atexit(SDL_Quit);
@@ -353,10 +378,11 @@ int worker_gl() {
 	if (shm->ge.gl_ctx == NULL) return 11;
 
 	while (!shm->done) {
-		//FIXME change for TRYWAIT for event handling (+delay)
+		alarm(1);
 		SEM_WAIT(&shm->worker_gl_can_render,10);
+		alarm(0);
 
-		if (!shm->paused) {
+		if (!shm->paused && !skip) {
 			// init / free if scene transition
 			if (lastscene != shm->scene) {
 				switch(lastscene) {
@@ -376,15 +402,16 @@ int worker_gl() {
 				// If scene init fail, skip to the next one
 				if (res) SCENE_NEXT; else lastscene = shm->scene;
 			}
-		}
 
-		// Compute current scene frame (gl part)
-		switch(shm->scene) {
-			case 0: res = scene00_next_gl(&shm->ge, &shm->s00e); break;
-			case 1: res = scene01_next_gl(&shm->ge, &shm->s01e); break;
-			case 2: res = scene02_next_gl(&shm->ge, &shm->s02e); break;
+			// Compute current scene frame (gl part)
+			switch(shm->scene) {
+				case 0: res = scene00_next_gl(&shm->ge, &shm->s00e); break;
+				case 1: res = scene01_next_gl(&shm->ge, &shm->s01e); break;
+				case 2: res = scene02_next_gl(&shm->ge, &shm->s02e); break;
+			}
+			if (res) SCENE_NEXT;
 		}
-		if (res) SCENE_NEXT;
+		if (skip) skip = 0;
 
 		// Event handling for the GL window (debug purposes)
 		while(SDL_PollEvent(&gl_ev)) {
diff --git a/src/main.h b/src/main.h
index 363a614..313dabf 100644
--- a/src/main.h
+++ b/src/main.h
@@ -11,6 +11,14 @@
 #define FBUF_W 256
 #define FBUF_H 256
 
+#ifdef DEBUG
+#define TRACE(hint) do { printf("%s(): %s\n", __func__, hint); fflush(stdout); } while(0)
+#define TRACE_ONCE(hint) if (firsttime) { printf("%s(): %s\n", __func__, hint); fflush(stdout); firsttime=0; }
+#else
+#define TRACE(hint)
+#define TRACE_ONCE(hint)
+#endif
+
 typedef struct {
 	// libcaca
 	caca_display_t *dp;
diff --git a/src/scene00.c b/src/scene00.c
index 0d6a02e..f418146 100644
--- a/src/scene00.c
+++ b/src/scene00.c
@@ -20,10 +20,12 @@
 #include "scene00.h"
 
 int scene00_init_gl(graphical_env_t *ge, scene00_env_t *se) {
+	TRACE("call");
 	return 0;
 }
 
 int scene00_init_sdl(graphical_env_t *ge, scene00_env_t *se) {
+	TRACE("call");
 	SDL_Surface *bmpSurf = SDL_LoadBMP("./res/eo1.bmp");
 	se->eo1 = SDL_CreateTextureFromSurface(ge->sdl_rndr, bmpSurf);
 	SDL_FreeSurface(bmpSurf);
@@ -32,20 +34,25 @@ int scene00_init_sdl(graphical_env_t *ge, scene00_env_t *se) {
 }
 
 int scene00_init_caca(graphical_env_t *ge, scene00_env_t *se) {
+	TRACE("call");
 	return 0;
 }
 
 void scene00_free_gl(graphical_env_t *ge, scene00_env_t *se) {
+	TRACE("call");
 }
 
 void scene00_free_sdl(graphical_env_t *ge, scene00_env_t *se) {
+	TRACE("call");
 	SDL_DestroyTexture(se->eo1); se->eo1=NULL;
 }
 
 void scene00_free_caca(graphical_env_t *ge, scene00_env_t *se) {
+	TRACE("call");
 }
 
 int scene00_next_gl(graphical_env_t *ge, scene00_env_t *se) {
+	static int firsttime=1; TRACE_ONCE("call");
 	return 0;
 }
 
@@ -53,6 +60,8 @@ int scene00_next_sdl(graphical_env_t *ge, scene00_env_t *se) {
 	// Shorthands
 	SDL_Renderer *r = ge->sdl_rndr;
 
+	static int firsttime=1; TRACE_ONCE("call");
+
 	// https://gist.github.com/Twinklebear/8265888
 	// https://forums.libsdl.org/viewtopic.php?p=51634
 
@@ -81,6 +90,8 @@ int scene00_next_caca(graphical_env_t *ge, scene00_env_t *se) {
 	int w = ge->w, h = ge->h;
 	Uint32 frame = ge->sc_framecount;
 
+	static int firsttime=1; TRACE_ONCE("call");
+
 	// "convert" the raw pixel stream from SDL to ASCII art on caca canevas
 	caca_dither_bitmap(cv, 0, 0, w, h, ge->d, ge->raw_target);
 
diff --git a/src/scene01.c b/src/scene01.c
index f8027c4..a2f1345 100644
--- a/src/scene01.c
+++ b/src/scene01.c
@@ -77,6 +77,7 @@ typedef enum t_attrib_id
 int scene01_init_gl(graphical_env_t *ge, scene01_env_t *se) {
 	GLuint vs, fs, program;
 
+	TRACE("call");
 	vs = glCreateShader(GL_VERTEX_SHADER);
 	fs = glCreateShader(GL_FRAGMENT_SHADER);
 
@@ -142,25 +143,31 @@ int scene01_init_gl(graphical_env_t *ge, scene01_env_t *se) {
 }
 
 int scene01_init_sdl(graphical_env_t *ge, scene01_env_t *se) {
+	TRACE("call");
 	return 0;
 }
 
 int scene01_init_caca(graphical_env_t *ge, scene01_env_t *se) {
+	TRACE("call");
 	return 0;
 }
 
 void scene01_free_gl(graphical_env_t *ge, scene01_env_t *se) {
+	TRACE("call");
 	//TODO
 }
 
 void scene01_free_sdl(graphical_env_t *ge, scene01_env_t *se) {
+	TRACE("call");
 }
 
 void scene01_free_caca(graphical_env_t *ge, scene01_env_t *se) {
+	TRACE("call");
 }
 
 int scene01_next_gl(graphical_env_t *ge, scene01_env_t *se) {
 	SDL_Renderer *r = ge->gl_rndr;
+	static int firsttime=1; TRACE_ONCE("call");
 
 	// https://gist.github.com/Twinklebear/8265888
 	// https://forums.libsdl.org/viewtopic.php?p=51634
@@ -179,6 +186,7 @@ int scene01_next_gl(graphical_env_t *ge, scene01_env_t *se) {
 }
 
 int scene01_next_sdl(graphical_env_t *ge, scene01_env_t *se) {
+	static int firsttime=1; TRACE_ONCE("call");
 	return 0;
 }
 
@@ -187,6 +195,7 @@ int scene01_next_caca(graphical_env_t *ge, scene01_env_t *se) {
 	caca_canvas_t *cv = ge->cv;
 	int w = ge->w, h = ge->h;
 	Uint32 frame = ge->sc_framecount;
+	static int firsttime=1; TRACE_ONCE("call");
 
 	// "convert" the raw pixel stream from SDL to ASCII art on caca canevas
 	caca_set_dither_gamma(ge->d, 1.0);
diff --git a/src/scene02.c b/src/scene02.c
index 03f02a4..f268f1f 100644
--- a/src/scene02.c
+++ b/src/scene02.c
@@ -20,32 +20,40 @@
 #include "scene02.h"
 
 int scene02_init_gl(graphical_env_t *ge, scene02_env_t *se) {
+	TRACE("call");
 	return 0;
 }
 
 int scene02_init_sdl(graphical_env_t *ge, scene02_env_t *se) {
+	TRACE("call");
 	return 0;
 }
 
 int scene02_init_caca(graphical_env_t *ge, scene02_env_t *se) {
+	TRACE("call");
 	return 0;
 }
 
 void scene02_free_gl(graphical_env_t *ge, scene02_env_t *se) {
+	TRACE("call");
 }
 
 void scene02_free_sdl(graphical_env_t *ge, scene02_env_t *se) {
+	TRACE("call");
 }
 
 void scene02_free_caca(graphical_env_t *ge, scene02_env_t *se) {
+	TRACE("call");
 }
 
 
 int scene02_next_gl(graphical_env_t *ge, scene02_env_t *se) {
+	static int firsttime=1; TRACE_ONCE("call");
 	return 0;
 }
 
 int scene02_next_sdl(graphical_env_t *ge, scene02_env_t *se) {
+	static int firsttime=1; TRACE_ONCE("call");
 	return 0;
 }
 
@@ -55,6 +63,8 @@ int scene02_next_caca(graphical_env_t *ge, scene02_env_t *se) {
 	//int w = ge->w, h = ge->h;
 	Uint32 frame = ge->sc_framecount;
 
+	static int firsttime=1; TRACE_ONCE("call");
+
 	caca_clear_canvas(cv);
 
 	if (frame >= 100) {
-- 
cgit v1.2.3