You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@harmony.apache.org by "Tim Ellison (JIRA)" <ji...@apache.org> on 2006/02/24 12:35:37 UTC

[jira] Resolved: (HARMONY-51) java.io.Writer : write(String) should write String as atomic operation.

     [ http://issues.apache.org/jira/browse/HARMONY-51?page=all ]
     
Tim Ellison resolved HARMONY-51:
--------------------------------

    Resolution: Fixed

Vladimir,

Fixed in LUNI module java.io.Writer at repo revision 380643.

I created a simpler test case and have committed it to SVN, but unfortunately it exposes a bug in the IBM VME code, so the test is disabled until that bug is resolved (when we get the exclusion list in place I'll exclude it only for the IBM VME and uncomment the test).

Please check that the fix fully resolves your problem.


> java.io.Writer : write(String) should write String as atomic operation.
> -----------------------------------------------------------------------
>
>          Key: HARMONY-51
>          URL: http://issues.apache.org/jira/browse/HARMONY-51
>      Project: Harmony
>         Type: Bug
>   Components: Classlib
>     Reporter: Vladimir Ivanov
>     Assignee: Tim Ellison

>
> java.io.Writer : write(String) should write String as atomic operation.
> Code to reproduce (Note, the increment of fields due to call of write(String ...) methods is occurred only after the assertion is checked):
> import java.io.*; 
>   
> public class test29 { 
>     public static void main(String args[]) { 
>             Object lock = new Object(); 
>             final MockWriter w = new MockWriter(lock); 
>   
>             class Thr extends Thread { 
>                 int seed; 
>   
>                 Thr(int seed) { 
>                     this.seed = seed; 
>                 } 
>   
>                 public void run() { 
>                     try { 
>                         switch (seed) { 
>                         case 0: 
>                             w.write(new char[] { 'a' }); 
>                             break; 
>                         case 1: 
>                             w.write("abcd".toCharArray(), 1, 1); 
>                             break; 
>                         case 2: 
>                                        w.write("c"); 
>                             break; 
>                         case 3: 
>                             w.write("abcd", 3, 1); 
>                             break; 
> 			default:
> 			    break;
>                         } 
>                     } catch (Throwable e) { 
>                         e.printStackTrace(); 
>                     } 
>                 } 
>             } 
>   
>             try {
> 	    Thr[] thrs = new Thr[4]; 
>             synchronized (lock) { 
>                 for (int i = 0; i < 4; ++i) { 
>                     thrs[i] = new Thr(i); 
>                     thrs[i].start(); 
> 	            Thread.yield(); 
>                 } 
>   
>                 Thread.sleep(3000); 
>   
>                 System.out.println("" + w.written['a'] + w.written['b'] + w.written['c'] + w.written['d']) ; 
>                 System.out.println(("" + w.written['a'] + w.written['b'] + w.written['c'] + w.written['d']).equals("1100") ? "PASSED" : "FAILED") ; 
>   
>             } 
>   
>             for (int i = 0; i < thrs.length; ++i) { 
>                thrs[i].join(); 
>             } 
>             w.close(); 
> 	    } catch (Exception e) {
> 		System.out.println("unex: " + e);
> 	    }
>     }
> } 
>   
> class MockWriter extends Writer { 
>     public int[] written = new int['z']; 
>   
>     MockWriter(Object lock) { 
>        super(lock); 
>     } 
>    
>   
>     public synchronized void close() throws IOException { 
>     } 
>   
>     public synchronized void flush() throws IOException { 
>     } 
>   
>     public void write(char[] arg0, int arg1, int arg2) throws IOException { 
>         if (arg1 < 0 || arg2 < 0) { 
>             throw new ArrayIndexOutOfBoundsException(); 
>         } 
>         for (int i = arg1; i < arg1 + arg2; ++i) { 
>             ++written[arg0[i]];
> 	    System.out.println("written.length=" + written.length + ", increment field: " + arg0[i]);
>         } 
>     } 
> } 
> Steps to Reproduce: 
> 1. Build Harmony (check-out on 2006-01-25) j2se subset as described in README.txt. 
> 2. Compile test29.java using BEA 1.4 javac 
> > javac -d . test29.java 
> 3. Run java using compatible VM (J9) 
> > java -showversion test29
> Output:
> C:\tmp\tmp17>C:\harmony\trunk\deploy\jre\bin\java -showversion test29
> java version 1.4.2 (subset)
> (c) Copyright 1991, 2005 The Apache Software Foundation or its licensors, as app
> licable.
> written.length=122, increment field: a
> written.length=122, increment field: b
> written.length=122, increment field: c
> 1110
> FAILED
> written.length=122, increment field: d
> C:\tmp\tmp17>C:\jrockit-j2sdk1.4.2_04\bin\java.exe -showversion test29
> java version "1.4.2_04"
> Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_04-b05)
> BEA WebLogic JRockit(TM) 1.4.2_04 JVM  (build ari-31788-20040616-1132-win-ia32, Native Threads, GC strategy: parallel)
> written.length=122, increment field: a
> written.length=122, increment field: b
> 1100
> PASSED
> written.length=122, increment field: d
> written.length=122, increment field: c
> C:\tmp\tmp17>
> Suggested fix: add one synchronized section to Writer.java: write(String) method
> -------------------------------------------
> old code:
> 	public void write(String str) throws IOException {
> 		char buf[] = new char[str.length()];
> 		str.getChars(0, buf.length, buf, 0);
> 		write(buf);
> 	}
> ------------------------------------------
> new code:
> 	public void write(String str) throws IOException {
> 		char buf[] = new char[str.length()];
> 		str.getChars(0, buf.length, buf, 0);
> 		synchronized (lock) {
> 			write(buf);
> 		}
> 	}
> -------------------------------------------
> junit test:
> ------------------------ WriterTest.java -------------------------------------------------
> import java.io.*; 
> import junit.framework.*; 
>   
> public class WriterTest extends TestCase { 
>     public static void main(String[] args) { 
>         junit.textui.TestRunner.run(WriterTest.class); 
>     } 
>     public void testWrite_String() { 
>             Object lock = new Object(); 
>             final MockWriter w = new MockWriter(lock); 
>   
>             class Thr extends Thread { 
>                 int seed; 
>   
>                 Thr(int seed) { 
>                     this.seed = seed; 
>                 } 
>   
>                 public void run() { 
>                     try { 
>                         switch (seed) { 
>                         case 0: 
>                             w.write(new char[] { 'a' }); 
>                             break; 
>                         case 1: 
>                             w.write("abcd".toCharArray(), 1, 1); 
>                             break; 
>                         case 2: 
>                                        w.write("c"); 
>                             break; 
>                         case 3: 
>                             w.write("abcd", 3, 1); 
>                             break; 
> 			default:
> 			    break;
>                         } 
>                     } catch (Throwable e) { 
>                         e.printStackTrace(); 
>                     } 
>                 } 
>             } 
>   
>             try {
>                 Thr[] thrs = new Thr[4]; 
>                 synchronized (lock) { 
>                     for (int i = 0; i < 4; ++i) { 
>                         thrs[i] = new Thr(i); 
>                         thrs[i].start(); 
> 	                Thread.yield(); 
>                     } 
>   
>                     Thread.sleep(3000); 
>   
>                     assertTrue(("" + w.written['a'] + w.written['b'] + w.written['c'] + w.written['d']).equals("1100")) ; 
>   
>                 } 
>   
>                 for (int i = 0; i < thrs.length; ++i) { 
>                    thrs[i].join(); 
>                 } 
>                 w.close(); 
> 	    } catch (Exception e) {
> 		System.out.println("unex: " + e);
> 	    }
>     }
> } 
>   
> class MockWriter extends Writer { 
>     public int[] written = new int['z']; 
>   
>     MockWriter(Object lock) { 
>        super(lock); 
>     } 
>    
>   
>     public synchronized void close() throws IOException { 
>     } 
>   
>     public synchronized void flush() throws IOException { 
>     } 
>   
>     public void write(char[] arg0, int arg1, int arg2) throws IOException { 
>         if (arg1 < 0 || arg2 < 0) { 
>             throw new ArrayIndexOutOfBoundsException(); 
>         } 
>         for (int i = arg1; i < arg1 + arg2; ++i) { 
>             ++written[arg0[i]];
>         } 
>     } 
> } 
>  

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira