Index: SerialImp.h =================================================================== RCS file: /usr/local/cvsroot/rxtx-devel/src/SerialImp.h,v retrieving revision 1.11.2.49 diff -u -r1.11.2.49 SerialImp.h --- SerialImp.h 5 Jul 2005 17:47:21 -0000 1.11.2.49 +++ SerialImp.h 17 May 2006 17:30:24 -0000 @@ -100,6 +100,7 @@ #if !defined(TIOCSERGETLSR) && !defined(WIN32) int writing; int output_buffer_empty_flag; + pthread_t drain_tid; #endif /* !TIOCSERGETLSR !WIN32 */ # if defined(TIOCGICOUNT) struct serial_icounter_struct osis; Index: SerialImp.c =================================================================== RCS file: /usr/local/cvsroot/rxtx-devel/src/SerialImp.c,v retrieving revision 1.46.2.188 diff -u -r1.46.2.188 SerialImp.c --- SerialImp.c 7 May 2006 23:58:59 -0000 1.46.2.188 +++ SerialImp.c 17 May 2006 17:30:25 -0000 @@ -714,7 +714,11 @@ ENTER( "RXTXPort:nativeClose" ); if (fd > 0) { - do { + report("nativeClose: discarding remaining datai (tcflush)\n"); + /* discard any incoming+outgoing data not yet read/sent */ + tcflush(fd, TCIOFLUSH); + do { + report("nativeClose: calling close\n"); result=CLOSE (fd); } while ( result < 0 && errno == EINTR ); UNLOCK( filename, pid ); @@ -1196,9 +1200,13 @@ report_verbose("drain_loop: looping\n"); #if defined(__sun__) /* FIXME: No time to test on all OS's for production */ - usleep(5000); + if (usleep(5000)) { + report("drain_loop: received EINTR"); + } #else - usleep(1000000); + if (usleep(1000000)) { + report("drain_loop: received EINTR"); + } #endif /* __sun__ */ /* system_wait(); @@ -1227,11 +1235,15 @@ report_verbose("drain_loop: writing not set\n"); } } - else + else if (errno != EINTR) { report("drain_loop: tcdrain bad fd\n"); goto end; } + else + { + report("drain_loop: received EINTR\n"); + } } end: report("------------------ drain_loop exiting ---------------------\n"); @@ -1274,9 +1286,9 @@ #if !defined(TIOCSERGETLSR) && !defined( WIN32 ) static void warn_sig_abort( int signo ) { + /* char msg[80]; sprintf( msg, "RXTX Recieved Signal %i\n", signo ); - /* report_error( msg ); */ } @@ -1290,6 +1302,9 @@ return: none exceptions: none comments: + this function is called from the event_loop or in other words + from the monitor thread. On systems !WIN32 and without TIOCSERGETLSR + it will create a new thread looping a call to tcdrain. ----------------------------------------------------------*/ int init_threads( struct event_info_struct *eis ) { @@ -1301,15 +1316,19 @@ report_time_start( ); report("init_threads: start\n"); + /* ignore child thread status changes */ sigemptyset(&newmask); sigaddset(&newmask, SIGCHLD); + + /* install our own signal hander */ newaction.sa_handler = warn_sig_abort; sigemptyset( &newaction.sa_mask ); #ifdef SA_INTERRUPT newaction.sa_flags = SA_INTERRUPT; #endif /* SA_INTERRUPT */ #ifdef SA_RESTART - newaction.sa_flags = SA_RESTART; + /* JOE: do not demand restart! we are handling EINTR */ +/* newaction.sa_flags = SA_RESTART;*/ #endif /* SA_RESTART */ sigaction(SIGABRT, &newaction, &oldaction); @@ -1333,6 +1352,7 @@ report("init_threads: creating drain_loop\n"); pthread_create( &tid, NULL, drain_loop, (void *) eis ); pthread_detach( tid ); + eis->drain_tid = tid; #endif /* TIOCSERGETLSR */ report("init_threads: get eis\n"); jeis = (*eis->env)->GetFieldID( eis->env, eis->jclazz, "eis", "J" ); @@ -4749,6 +4769,10 @@ #ifdef WIN32 termios_interrupt_event_loop( index->fd, 1 ); #endif /* WIN32 */ +#if !defined(TIOCSERGETLSR) && !defined(WIN32) + /* make sure that the drainloop unblocks from tcdrain */ + pthread_kill(index->drain_tid, SIGABRT); +#endif report("interruptEventLoop: interrupted\n"); } Index: RXTXPort.java =================================================================== RCS file: /usr/local/cvsroot/rxtx-devel/src/RXTXPort.java,v retrieving revision 1.27.2.70 diff -u -r1.27.2.70 RXTXPort.java --- RXTXPort.java 30 Jan 2006 02:50:57 -0000 1.27.2.70 +++ RXTXPort.java 17 May 2006 17:30:26 -0000 @@ -811,27 +811,22 @@ if (debug) z.reportln( " RXTXPort:calling monThread.join()"); try { - monThread.join(1000); - } catch (Exception ex) { - /* yikes */ - ex.printStackTrace(); - } - if (debug) - z.reportln( " RXTXPort:waiting on isAlive()"); - while( monThread.isAlive() ) - { - if ( debug ) - z.reportln( " MonThread is still alive!"); - try { - monThread.join(1000); - Thread.sleep( 1000 ); - } catch( Exception e ){} - //monThread.stop(); + + // wait a reasonable moment for the death of the monitor thread + monThread.join(3000); + } catch (InterruptedException ex) { + // somebody called interrupt() on us (ie wants us to abort) + // we dont propagate InterruptedExceptions so lets re-set the flag + Thread.currentThread().interrupt(); + return; + } + + if ( debug && monThread.isAlive() ) + z.reportln( " MonThread is still alive!"); + } } - if (debug) - z.reportln( " RXTXPort:calling gc()"); monThread = null; SPEventListener = null; MonitorThreadLock = false; @@ -1011,20 +1006,32 @@ /** */ boolean closeLock = false; - public synchronized void close() + public void close() { - if (debug) - z.reportln( "RXTXPort:close( " + this.name + " )"); - if( closeLock ) return; - closeLock = true; - while( IOLocked > 0 ) - { - if( debug ) - z.reportln("IO is locked " + IOLocked); - try { - Thread.sleep(500); - } catch( Exception e ) {} + synchronized (this) { + if (debug) + z.reportln( "RXTXPort:close( " + this.name + " )"); + + while( IOLocked > 0 ) + { + if( debug ) + z.reportln("IO is locked " + IOLocked); + try { + this.wait(500); + } catch( InterruptedException ie ) { + // somebody called interrupt() on us + // we obbey and return without without closing the socket + Thread.currentThread().interrupt(); + return; + } + } + + // we set the closeLock after the above check because we might + // have returned without proceeding + if( closeLock ) return; + closeLock = true; } + if ( fd <= 0 ) { z.reportln( "RXTXPort:close detected bad File Descriptor" );