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