FULL PRODUCT VERSION : java version "1.6.0_02" Java(TM) SE Runtime Environment (build 1.6.0_02-b05) Java HotSpot(TM) Client VM (build 1.6.0_02-b05, mixed mode, sharing) (from Debian) also java version "1.6.0_02-ea" Java(TM) SE Runtime Environment (build 1.6.0_02-ea-b02) Java HotSpot(TM) Client VM (build 1.6.0_02-ea-b02, mixed mode) (latest JRE from the Sun homepage) ADDITIONAL OS VERSION INFORMATION : Linux 2.6.22-1-686 #1 SMP Sun Jul 29 14:37:42 UTC 2007 i686 GNU/Linux EXTRA RELEVANT SYSTEM CONFIGURATION : Cups 1.3.0 A DESCRIPTION OF THE PROBLEM : Consider the following example program: public static void main(String[] args) { final PrintService[] services = PrintServiceLookup. lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, null); System.err.println("found " + services.length); } If run repeatedly, this program will output "found 0" or "found 2", where 2 is the actual number of CUPS printers installed (both raw printers to a file). The run that outputs "found 0" is thus wrong. It seems that each time the correct output is produced, the method sun.print.UnixPrintServiceLookup.refreshServices() has been invoked from the thread PrinterChangeListener (defined in the same class), while each time the wrong output is produced, refreshServices() has been invoked from the calling thread through getPrintServices(). Further analysis shows that after refreshServices() has been invoked from the calling thread, the program throws a NullPointerException in PrintServiceLookup:367 in method getServices. It seems that services[1] is null even though getPrintServices() returned an array which had a non-null element 1. This leads to the conclusion that the array must have been modified in the meantime, which may be possible if the aforementioned PrinterChangeListener has been invoked and modified this array. If this was indeed a classic concurrency problem where PrinterChangeListener modifies the array that is used somewhere else, then setting the System Property "sun.java2d.print.polling" to "false" should prove as a viable workaround, which is indeed the case. The program invoked with -Dsun.java2d.print.polling=false seems to always output "found 2" after a few hundred runs. Further inspection of UnixPrintServiceLookup reveals that refreshServices indeed modifies the members of the array variable printServices directly, which has been returned and is used by the caller as the abovementioned services from getPrintServices(). It thus seems plausible that the problem occurs because of these concurrency issues, which would also explain why it only occurs sometimes. In any case, care must be taken to not modify any element of printServices at all, but to reset the member variable to a new array, as it is returned from getPrintServices(). This is, honestly, a pretty stupid bug which should not happen if a programmer knows anything about concurrency, which should be the case if this same programmer uses threads for the polling. REPRODUCIBILITY : This bug can be reproduced occasionally. CUSTOMER SUBMITTED WORKAROUND : invoke System.setProperty("sun.java2d.print.polling", "false"); as first line of your program.
|