nanogui: multithreading issues


Previous by date: 3 Sep 2007 15:43:01 +0100 Re: nano-X: GsRead failed -1 0: 131, Greg Haerr
Next by date: 3 Sep 2007 15:43:01 +0100 Corrupted Packet Nano-X, Detzner, Peter
Previous in thread: 3 Sep 2007 15:43:01 +0100 Re: multithreading issues, Greg Haerr
Next in thread:

Subject: Re: [nanogui] multithreading issues
From: ####@####.####
Date: 3 Sep 2007 15:43:01 +0100
Message-Id: <20070903094251.xrllncgo0kcw8kcg@localhost>

Hi Greg,

Sorry for the delay.
Now I revised my patches and added also an application, which shows  
the problem, as you requested and inlined it all in the mail instead  
of attachments to make your mailing list server more happy.

The non void nano-x calls are done from an init function (I want to  
change this later on)
Afterwards two threads are created. One, which handles the key pressed  
events and another one, which draws some stuff.

Here is the demo app:

---------->

#include <stdio.h>
#include <stdlib.h>
#define MWINCLUDECOLORS
#include "nano-X.h"
#include <pthread.h>

GR_WINDOW_ID wid;
GR_GC_ID gc;
GR_SCREEN_INFO	si;

void init();
void handle_events(GR_EVENT * event);
void handle_graphics();

void init()
{
         GrGetScreenInfo(&si);
	wid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, si.cols, si.rows, 1, GRAY, WHITE);
         GrSelectEvents(wid, GR_EVENT_MASK_KEY_DOWN);
	GrMapWindow(wid);

	gc = GrNewGC();
	GrSetGCForeground(gc, RED);
}

void handle_events(GR_EVENT * event)
{
         while (1)
	{
		printf("------------------------------------------------------\n");
		GrGetNextEvent(event);
		if(event != NULL)
		{
			switch (event->type)
			{
				case GR_EVENT_TYPE_KEY_DOWN:
					printf("KEY PRESSED \n");
					break;
			}
		}
		printf("------------------------------------------------------\n");
	}
}

void handle_graphics()
{
         int i;

	printf("Inside handle_graphics\n");

	for (i=1; i<10; i++)
	{
         	GrFillRect(wid, gc, 250-i*20, 230, 10, 50);
		GrFlush();
         	sleep(1);
         }
}

int main(int argc,char **argv) {
	GR_EVENT event;
	pthread_t  p_thread_events;
	pthread_t  p_thread_graphics;

	if (GrOpen() < 0) {
		fprintf(stderr,"cannot open graphics\n");
		exit(1);
	}

	init();
	pthread_create(&p_thread_events, NULL, (void *)handle_events, &event);
	pthread_create(&p_thread_graphics, NULL, (void *)handle_graphics, NULL);
	sleep(100);
	GrClose();
}


<----------

If I don't apply any patches, my system gets stuck (does not draw)  
because GrGetNextEvent() holds a lock an so the other thread can not  
draw.


Here are the patches:

---------------->

Index: microwin/src/nanox/client.c
===================================================================
--- microwin.orig/src/nanox/client.c
+++ microwin/src/nanox/client.c
@@ -989,8 +989,22 @@ _GrGetNextEventTimeout(GR_EVENT *ep, GR_
  		to.tv_usec = (timeout % 1000) * 1000;
  	}

-	if((e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to : NULL))>0) {
-		int fd;
+
+        /* --> */
+        /* replaced: */
+        /*
+        if((e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to :  
NULL))>0) {
+        */
+        /* with: */
+        /* give Nano-X calls from other threads a chance to run by  
releasing the lock */
+        UNLOCK(&nxGlobalLock);
+        e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to : NULL);
+        /* we lock the GlobalLock again, which was unlocked a few  
lines above */
+        LOCK(&nxGlobalLock);
+        if(e>0)
+        {
+        /* <-- */
+                int fd;

  		if(FD_ISSET(nxSocket, &rfds)) {
  			/*

<-------------------

-------------------->

Index: microwin/src/nanox/srvmain.c
===================================================================
--- microwin.orig/src/nanox/srvmain.c
+++ microwin/src/nanox/srvmain.c
@@ -596,6 +596,7 @@ GsSelect(GR_TIMEOUT timeout)
  	int	setsize = 0;
  	struct timeval tout;
  	struct timeval *to;
+
  #if NONETWORK
  	int	fd;
  #endif
@@ -708,7 +709,25 @@ GsSelect(GR_TIMEOUT timeout)
  	}

  	/* Wait for some input on any of the fds in the set or a timeout: */
-	if((e = select(setsize+1, &rfds, NULL, NULL, to)) > 0) {
+
+	/* --> */
+        /* replaced: */
+        /*
+	if((e = select(setsize+1, &rfds, NULL, NULL, to)) > 0)
+        */
+        /* with: */
+#if NONETWORK
+        SERVER_UNLOCK();
+#endif
+        /* now we can call select, which will wait forever for an  
event to arrive */
+	e = select(setsize+1, &rfds, NULL, NULL, to);
+        /* we lock the GlobalLock again, which was unlocked a few  
lines above */
+#if NONETWORK
+        SERVER_LOCK();
+#endif
+        if(e>0)
+        /* <-- */
+        {
  		/* If data is present on the mouse fd, service it: */
  		if(mouse_fd >= 0 && FD_ISSET(mouse_fd, &rfds))
  			while(GsCheckMouseEvent())


<--------------------

With LINK_APP_INTO_SERVER, since all the Nano-X functions seem to  
reentrant, everything should work fine from multiple threads, as far  
as I can imagine.
It looks like the only communication, which is done through IPC is  
between e.g. mouse-server and keyboard-server.

Also the client/server approach should work, but I guess this needs  
some more thought about the protocol how the server replies to the  
client.

Also I noted, that because MW_FEATURE_TIMERS is enabled in srvmain.c  
select calls GdGetNextTimeout, which makes it timeout.

It looks like there is some CPU overhead by letting select time out  
due to this frequent polling. I guess it would be fine to let select  
only unblock in case there are new events coming in, or to increase  
the timeout for e.g. a screen saver.
I don't use timers from my application (for now), so do I really need this?

Regards,

Robert



Previous by date: 3 Sep 2007 15:43:01 +0100 Re: nano-X: GsRead failed -1 0: 131, Greg Haerr
Next by date: 3 Sep 2007 15:43:01 +0100 Corrupted Packet Nano-X, Detzner, Peter
Previous in thread: 3 Sep 2007 15:43:01 +0100 Re: multithreading issues, Greg Haerr
Next in thread:


Powered by ezmlm-browse 0.20.