[Title] enhance synchronization of skin socket commnuication
authorSon Hyunjun <hj79.son@samsung.com>
Wed, 18 Apr 2012 12:55:30 +0000 (21:55 +0900)
committerSon Hyunjun <hj79.son@samsung.com>
Wed, 18 Apr 2012 12:55:30 +0000 (21:55 +0900)
[Type] Enhancement
[Module] Skin
[Priority] Minor
[CQ#]
[Redmine#]
[Problem]
[Cause]
[Solution]

Change-Id: I38c2e3c68517db9e99f4e379a28fc031da402239

tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java
tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java
tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java
tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java

index b0e1f8533074ebb0cdb5733f69435615732ffd5f..9f9c95d31d0446b7e7150489e3a97a7b34ae820b 100644 (file)
@@ -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<SkinSendData> 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<SkinSendData>();
+
+                       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
index 653cb1138e6c561811cd8af62fb6b95f87232412..be8d2bd3fca3411e26fc4e0378f6a219e9cc0ebe 100644 (file)
@@ -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;
index d5c79fd13596d43431a29a90f458d9bf1b068d41..fd9661c177914b63331012517b1cb2f652e23870 100644 (file)
@@ -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 ) {
index ff7209ff19161a6394ed174d67ed50d093ea13bb..7ae9c676efdac9296cdfc04cdc96e8ea04a7103a 100644 (file)
@@ -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." );
                }
 
        }