From 8482d30a001be201c4581db268bc64b6855526af Mon Sep 17 00:00:00 2001 From: Son Hyunjun Date: Wed, 18 Apr 2012 21:55:30 +0900 Subject: [PATCH] [Title] enhance synchronization of skin socket commnuication [Type] Enhancement [Module] Skin [Priority] Minor [CQ#] [Redmine#] [Problem] [Cause] [Solution] Change-Id: I38c2e3c68517db9e99f4e379a28fc031da402239 --- .../skin/comm/sock/SocketCommunicator.java | 271 +++++++++++++++--- .../skin/dialog/DetailInfoDialog.java | 53 +--- .../tizen/emulator/skin/log/SkinLogger.java | 11 +- .../skin/screenshot/ScreenShotDialog.java | 64 +---- 4 files changed, 258 insertions(+), 141 deletions(-) diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java index b0e1f85330..9f9c95d31d 100644 --- a/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java +++ b/tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java @@ -36,6 +36,9 @@ import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -45,6 +48,7 @@ import java.util.logging.Logger; import org.tizen.emulator.skin.EmulatorSkin; import org.tizen.emulator.skin.comm.ICommunicator; +import org.tizen.emulator.skin.comm.ICommunicator.SendCommand; import org.tizen.emulator.skin.comm.sock.data.ISendData; import org.tizen.emulator.skin.comm.sock.data.StartData; import org.tizen.emulator.skin.config.EmulatorConfig; @@ -65,31 +69,27 @@ public class SocketCommunicator implements ICommunicator { private boolean isTransferState; private byte[] receivedData; + private long sleep; + private long maxWaitTime; + private Timer timer; + private DataTranfer() { } - private void reset() { - receivedData = null; - isTransferState = true; - } - private void setData( byte[] data ) { this.receivedData = data; isTransferState = false; } - public synchronized boolean isTransferState() { - return isTransferState; - } - - public synchronized byte[] getReceivedData() { - return receivedData; - } - } public static final int HEART_BEAT_INTERVAL = 1; //second public static final int HEART_BEAT_EXPIRE = 5; + + public final static int SCREENSHOT_WAIT_INTERVAL = 3; // milli-seconds + public final static int SCREENSHOT_WAIT_LIMIT = 3000; // milli-seconds + public final static int DETAIL_INFO_WAIT_INTERVAL = 1; // milli-seconds + public final static int DETAIL_INFO_WAIT_LIMIT = 3000; // milli-seconds private static int reqId; @@ -104,15 +104,17 @@ public class SocketCommunicator implements ICommunicator { private DataInputStream dis; private DataOutputStream dos; - private DataTranfer dataTransfer; - private AtomicInteger heartbeatCount; - private boolean isTerminated; + private boolean isSensorDaemonStarted; private ScheduledExecutorService heartbeatExecutor; - private boolean isSensorDaemonStarted; + private DataTranfer screenShotDataTransfer; + private DataTranfer detailInfoTransfer; + private Thread sendThread; + private ConcurrentLinkedQueue sendQueue; + public SocketCommunicator( EmulatorConfig config, int uId, int windowHandleId, EmulatorSkin skin ) { this.config = config; @@ -120,7 +122,13 @@ public class SocketCommunicator implements ICommunicator { this.windowHandleId = windowHandleId; this.skin = skin; - this.dataTransfer = new DataTranfer(); + this.screenShotDataTransfer = new DataTranfer(); + this.screenShotDataTransfer.sleep = SCREENSHOT_WAIT_INTERVAL; + this.screenShotDataTransfer.maxWaitTime = SCREENSHOT_WAIT_LIMIT; + + this.detailInfoTransfer = new DataTranfer(); + this.detailInfoTransfer.sleep = DETAIL_INFO_WAIT_INTERVAL; + this.detailInfoTransfer.maxWaitTime = DETAIL_INFO_WAIT_LIMIT; this.heartbeatCount = new AtomicInteger( 0 ); this.heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(); @@ -144,6 +152,43 @@ public class SocketCommunicator implements ICommunicator { try { + sendQueue = new ConcurrentLinkedQueue(); + + sendThread = new Thread() { + @Override + public void run() { + + while ( true ) { + + synchronized ( sendThread ) { + try { + sendThread.wait(); + } catch ( InterruptedException e ) { + logger.log( Level.SEVERE, e.getMessage(), e ); + } + } + + SkinSendData sendData = null; + while ( true ) { + sendData = sendQueue.poll(); + if ( null != sendData ) { + sendToQEMUInternal( sendData ); + } else { + break; + } + } + + if ( isTerminated ) { + break; + } + + } + + } + }; + + sendThread.start(); + dis = new DataInputStream( socket.getInputStream() ); dos = new DataOutputStream( socket.getOutputStream() ); @@ -223,27 +268,13 @@ public class SocketCommunicator implements ICommunicator { } case SCREEN_SHOT_DATA: { logger.info( "received SCREEN_SHOT_DATA from QEMU." ); - - synchronized ( dataTransfer ) { - byte[] imageData = readData( dis, length ); - dataTransfer.setData( imageData ); - dataTransfer.notifyAll(); - } - - logger.info( "finish receiving image data from QEMU." ); + receiveData( screenShotDataTransfer, length ); break; } case DETAIL_INFO_DATA: { logger.info( "received DETAIL_INFO_DATA from QEMU." ); - - synchronized ( dataTransfer ) { - byte[] infoData = readData( dis, length ); - dataTransfer.setData( infoData ); - dataTransfer.notifyAll(); - } - - logger.info( "finish receiving info data from QEMU." ); + receiveData( detailInfoTransfer, length ); break; } @@ -257,7 +288,6 @@ public class SocketCommunicator implements ICommunicator { case SHUTDOWN: { logger.info( "received RESPONSE_SHUTDOWN from QEMU." ); sendToQEMU( SendCommand.RESPONSE_SHUTDOWN, null ); - isTerminated = true; terminate(); break; } @@ -276,6 +306,32 @@ public class SocketCommunicator implements ICommunicator { } + private void receiveData( DataTranfer dataTransfer, int length ) throws IOException { + + synchronized ( dataTransfer ) { + + if( null != dataTransfer.timer ) { + dataTransfer.timer.cancel(); + } + + byte[] data = readData( dis, length ); + + if( null != data ) { + logger.info( "finished receiving data from QEMU." ); + }else { + logger.severe( "Fail to receiving data from QEMU." ); + } + + dataTransfer.isTransferState = false; + dataTransfer.timer = null; + + dataTransfer.setData( data ); + dataTransfer.notifyAll(); + + } + + } + private byte[] readData( DataInputStream is, int length ) throws IOException { if ( 0 >= length ) { @@ -312,18 +368,79 @@ public class SocketCommunicator implements ICommunicator { } - public synchronized void sendToQEMU( SendCommand command, ISendData data, boolean useDataTransfer ) { + public synchronized DataTranfer sendToQEMU( SendCommand command, ISendData data, boolean useDataTransfer ) { + + DataTranfer dataTranfer = null; + if ( useDataTransfer ) { - this.dataTransfer.reset(); + + if ( SendCommand.SCREEN_SHOT.equals( command ) ) { + dataTranfer = resetDataTransfer( screenShotDataTransfer ); + } else if ( SendCommand.DETAIL_INFO.equals( command ) ) { + dataTranfer = resetDataTransfer( detailInfoTransfer ); + } } + sendToQEMU( command, data ); + + return dataTranfer; + } + + private DataTranfer resetDataTransfer( final DataTranfer dataTransfer ) { + + synchronized ( dataTransfer ) { + + if ( dataTransfer.isTransferState ) { + logger.severe( "Already transter state for getting data." ); + return null; + } + + dataTransfer.isTransferState = true; + + Timer timer = new Timer(); + dataTransfer.timer = timer; + TimerTask timerTask = new TimerTask() { + @Override + public void run() { + synchronized ( dataTransfer ) { + dataTransfer.isTransferState = false; + dataTransfer.timer = null; + dataTransfer.receivedData = null; + } + } + }; + timer.schedule( timerTask, dataTransfer.maxWaitTime ); + + return dataTransfer; + + } + + } + @Override - public synchronized void sendToQEMU( SendCommand command, ISendData data ) { + public void sendToQEMU( SendCommand command, ISendData data ) { + + sendQueue.add( new SkinSendData( command, data ) ); + + synchronized ( sendThread ) { + sendThread.notifyAll(); + } + + } + + private void sendToQEMUInternal( SkinSendData sendData ) { try { + if( null == sendData ) { + return; + } + + SendCommand command = sendData.getCommand(); + ISendData data = sendData.getSendData(); + reqId = ( Integer.MAX_VALUE == reqId ) ? 0 : ++reqId; ByteArrayOutputStream bao = new ByteArrayOutputStream(); @@ -366,6 +483,48 @@ public class SocketCommunicator implements ICommunicator { } + public byte[] getReceivedData( DataTranfer dataTranfer ) { + + if( null == dataTranfer ) { + return null; + } + + synchronized ( dataTranfer ) { + + int count = 0; + byte[] receivedData = null; + long sleep = dataTranfer.sleep; + long maxWaitTime = dataTranfer.maxWaitTime; + int limitCount = (int) ( maxWaitTime / sleep ); + + while ( dataTranfer.isTransferState ) { + + if ( limitCount < count ) { + logger.severe( "time out for receiving data from skin server." ); + dataTranfer.receivedData = null; + break; + } + + try { + dataTranfer.wait( sleep ); + } catch ( InterruptedException e ) { + logger.log( Level.SEVERE, e.getMessage(), e ); + } + + count++; + logger.info( "wait data... count:" + count ); + + } + + receivedData = dataTranfer.receivedData; + dataTranfer.receivedData = null; + + return receivedData; + + } + + } + public Socket getSocket() { return socket; } @@ -389,19 +548,27 @@ public class SocketCommunicator implements ICommunicator { heartbeatCount.set( 0 ); } - public DataTranfer getDataTranfer() { - return dataTransfer; - } - @Override public void terminate() { + + isTerminated = true; + if ( null != heartbeatExecutor ) { heartbeatExecutor.shutdownNow(); } + + if( null != sendThread ) { + synchronized ( sendThread ) { + sendThread.notifyAll(); + } + } + IOUtil.closeSocket( socket ); + synchronized ( this ) { skin.shutdown(); } + } public void resetSkin( EmulatorSkin skin ) { @@ -411,3 +578,23 @@ public class SocketCommunicator implements ICommunicator { } } + +class SkinSendData { + + private SendCommand command; + private ISendData data; + + public SkinSendData( SendCommand command, ISendData data ) { + this.command = command; + this.data = data; + } + + public SendCommand getCommand() { + return command; + } + + public ISendData getSendData() { + return data; + } + +} \ No newline at end of file diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java index 653cb1138e..be8d2bd3fc 100644 --- a/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java +++ b/tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java @@ -32,7 +32,6 @@ package org.tizen.emulator.skin.dialog; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map.Entry; -import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.swt.SWT; @@ -61,8 +60,6 @@ import org.tizen.emulator.skin.util.StringUtil; */ public class DetailInfoDialog extends SkinDialog { - public final static int DETAIL_INFO_WAIT_INTERVAL = 1; // milli-seconds - public final static int DETAIL_INFO_WAIT_LIMIT = 3000; // milli-seconds public final static String DATA_DELIMITER = "#"; private Logger logger = SkinLogger.getSkinLogger( DetailInfoDialog.class ).getLogger(); @@ -137,52 +134,14 @@ public class DetailInfoDialog extends SkinDialog { String infoData = null; - communicator.sendToQEMU( SendCommand.DETAIL_INFO, null, true ); - DataTranfer dataTranfer = communicator.getDataTranfer(); - - int count = 0; - boolean isFail = false; - byte[] receivedData = null; - int limitCount = DETAIL_INFO_WAIT_LIMIT / DETAIL_INFO_WAIT_INTERVAL; - - synchronized ( dataTranfer ) { - - while ( dataTranfer.isTransferState() ) { - - if ( limitCount < count ) { - isFail = true; - break; - } - - try { - dataTranfer.wait( DETAIL_INFO_WAIT_INTERVAL ); - } catch ( InterruptedException e ) { - logger.log( Level.SEVERE, e.getMessage(), e ); - } - - count++; - logger.info( "wait detail info data... count:" + count ); - - } - - receivedData = dataTranfer.getReceivedData(); - - } - - if ( isFail ) { - - logger.severe( "Fail to get detail info from server." ); - SkinUtil.openMessage( shell, null, "Internal error.", SWT.ICON_ERROR, config ); + DataTranfer dataTranfer = communicator.sendToQEMU( SendCommand.DETAIL_INFO, null, true ); + byte[] receivedData = communicator.getReceivedData( dataTranfer ); + if ( null != receivedData ) { + infoData = new String( receivedData ); } else { - - if ( null != receivedData ) { - infoData = new String( receivedData ); - } else { - logger.severe( "Received detail info is null" ); - SkinUtil.openMessage( shell, null, "Internal error.", SWT.ICON_ERROR, config ); - } - + logger.severe( "Fail to get detail info." ); + SkinUtil.openMessage( shell, null, "Fail to get detail info.", SWT.ICON_ERROR, config ); } return infoData; diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java index d5c79fd135..fd9661c177 100644 --- a/tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java +++ b/tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java @@ -113,6 +113,15 @@ public class SkinLogger { File dir = new File( path + LOG_FOLDER ); dir.mkdir(); + // delete .lck files after abnomal skin termination + File[] listFiles = dir.listFiles(); + for ( File f : listFiles ) { + String name = f.getName(); + if ( !FILE_NAME.equals( name ) && name.startsWith( FILE_NAME ) ) { + f.delete(); + } + } + File file = new File( dir + File.separator + FILE_NAME ); if( !file.exists() ) { try { @@ -127,7 +136,7 @@ public class SkinLogger { return; } } - + try { fileHandler = new FileHandler( file.getAbsolutePath(), false ); } catch ( SecurityException e1 ) { diff --git a/tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java b/tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java index ff7209ff19..7ae9c676ef 100644 --- a/tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java +++ b/tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java @@ -82,9 +82,6 @@ public class ScreenShotDialog { public final static String DEFAULT_FILE_EXTENSION = "png"; - public final static int SCREENSHOT_WAIT_INTERVAL = 3; // milli-seconds - public final static int SCREENSHOT_WAIT_LIMIT = 3000; // milli-seconds - public final static int RED_MASK = 0x0000FF00; public final static int GREEN_MASK = 0x00FF0000; public final static int BLUE_MASK = 0xFF000000; @@ -219,62 +216,27 @@ public class ScreenShotDialog { private void capture() throws ScreenShotException { - communicator.sendToQEMU( SendCommand.SCREEN_SHOT, null, true ); - DataTranfer dataTranfer = communicator.getDataTranfer(); - - int count = 0; - boolean isFail = false; - byte[] receivedData = null; - int limitCount = SCREENSHOT_WAIT_LIMIT / SCREENSHOT_WAIT_INTERVAL; - - synchronized ( dataTranfer ) { - - while ( dataTranfer.isTransferState() ) { - - if ( limitCount < count ) { - isFail = true; - break; - } - - try { - dataTranfer.wait( SCREENSHOT_WAIT_INTERVAL ); - } catch ( InterruptedException e ) { - logger.log( Level.SEVERE, e.getMessage(), e ); - } + DataTranfer dataTranfer = communicator.sendToQEMU( SendCommand.SCREEN_SHOT, null, true ); + byte[] receivedData = communicator.getReceivedData( dataTranfer ); - count++; - logger.info( "wait image data... count:" + count ); + if ( null != receivedData ) { + if ( null != this.image ) { + this.image.dispose(); } - receivedData = dataTranfer.getReceivedData(); + int width = config.getArgInt( ArgsConstants.RESOLUTION_WIDTH ); + int height = config.getArgInt( ArgsConstants.RESOLUTION_HEIGHT ); + ImageData imageData = new ImageData( width, height, COLOR_DEPTH, paletteData, 1, receivedData ); - } - - if ( !isFail ) { - - if ( null != receivedData ) { - - if ( null != this.image ) { - this.image.dispose(); - } + RotationInfo rotation = getCurrentRotation(); + imageData = rotateImageData( imageData, rotation ); - int width = config.getArgInt( ArgsConstants.RESOLUTION_WIDTH ); - int height = config.getArgInt( ArgsConstants.RESOLUTION_HEIGHT ); - ImageData imageData = new ImageData( width, height, COLOR_DEPTH, paletteData, 1, receivedData ); - - RotationInfo rotation = getCurrentRotation(); - imageData = rotateImageData( imageData, rotation ); - - this.image = new Image( Display.getDefault(), imageData ); - imageCanvas.redraw(); - - } else { - throw new ScreenShotException( "Received image data is null." ); - } + this.image = new Image( Display.getDefault(), imageData ); + imageCanvas.redraw(); } else { - throw new ScreenShotException( "Fail to received image data." ); + throw new ScreenShotException( "Fail to get image data." ); } } -- 2.34.1