Subject:
multi-threaded app: problem and suggestion; patch
From:
Petr Ovtchenkov ####@####.####
Date:
11 Aug 2005 07:32:34 +0100
Message-Id: <200508111032.31592.ptr@island.plnet.ru>
The design of nanoX lead to problems during usage in multi-threaded
applications. Let's consider:
thread 1 (windows creation):
----------------------------------------------
mwid = GrNewWindow( parent.mwid, _g._x, _g._y, _g._w, _g._h, /* _b._w */2,
_bg, /* _b._c */ RED );
if ( ev_mask != 0 ) {
GrSelectEvents( mwid, ev_mask );
}
GrMapWindow( mwid );
GrFlush();
....
GrDrawImageToFit( mwid, _gc, _g.x(), _g.y(), _g.width(), _g.height(),
_i2->id() );
....
mwid2 = GrNewWindow( parent.mwid, _g._x, _g._y, _g._w, _g._h, /* _b._w */2,
_bg, /* _b._c */ RED );
if ( ev_mask != 0 ) {
GrSelectEvents( mwid2, ev_mask );
}
GrMapWindow( mwid2 );
GrFlush();
GrCreateFont( (GR_CHAR *)"koi8x13.pcf.gz", 0, 0 );
GrSetGCForeground( _gc, fg );
GrSetGCBackground( _gc, bg );
GrSetGCFont( _gc, _fid );
....
GrText( imwid2, _gc, x, y, (void *)i->data(), i->size(), GR_TFASCII );
----------------------------------------------
thread 2 (main loop):
----------------------------------------------
GR_EVENT ev;
while ( !some_condition ) {
GrGetNextEvent(&ev);
switch ( ev.type ) {
case GR_EVENT_TYPE_ERROR:
/* cerr << "GR_EVENT_TYPE_ERROR" << endl; */
break;
case GR_EVENT_TYPE_NONE:
/* cerr << "GR_EVENT_TYPE_NONE" << endl; */
break;
case GR_EVENT_TYPE_EXPOSURE:
/*
{
__impl::Locker lock( map_lk );
Event_base<NX_EvExposure> event( EV_NX_EXPOSURE );
// cerr << mw_stem_map[ev.exposure.wid] << endl;
event.dest( mw_stem_map[ev.exposure.wid] );
event.value() = ev.exposure;
dummy.Send( event );
cerr << "GR_EVENT_TYPE_EXPOSURE" << endl;
}
*/
break;
....
}
}
----------------------------------------------
This code lead to deadlock, due to all Window-related calls lock on mutex when
perform critical operation under global data in thread 1, and GrGetNextEvent
do lock on same mutex and call select() that wait event:
GR_GC_ID
GrNewGC(void)
{
...
LOCK(&nxGlobalLock);
...
UNLOCK(&nxGlobalLock);
...
}
...
void
GrServiceSelect(void *rfdset, GR_FNCALLBACKEVENT fncb)
{
...
LOCK(&nxGlobalLock);
...
select(setsize+1, &rfds, NULL, NULL, timeout ? &to : NULL));
...
UNLOCK(&nxGlobalLock);
}
The same behavior on server side (this significant in case when you link nanoX
server inside application).
The solution: when you waiting on select() lock not required.
In attached patch I add XXGrEvent( GR_EVENT *ev ) functions, that used instead
of GrGetNextEvent. This function on src/nanox/client.c is clean (it in use
for client-server approach), while code in src/nanox/srvfunc.c and
src/nanox/srvmain.c is like hack and revision required.
Patch is against current CVS.
Bests,
- ptr
[Content type text/x-diff not shown. Download]