< prev index next >

src/java.base/share/classes/java/lang/ProcessBuilder.java

Print this page
imported patch ProcessEnvironment-race

@@ -23,10 +23,12 @@
  * questions.
  */
 
 package java.lang;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;

@@ -207,11 +209,11 @@
      * @param  command the list containing the program and its arguments
      */
     public ProcessBuilder(List<String> command) {
         if (command == null)
             throw new NullPointerException();
-        this.command = command;
+        COMMAND.setRelease(this, command);
     }
 
     /**
      * Constructs a process builder with the specified operating
      * system program and arguments.  This is a convenience

@@ -222,13 +224,14 @@
      * command.
      *
      * @param command a string array containing the program and its arguments
      */
     public ProcessBuilder(String... command) {
-        this.command = new ArrayList<>(command.length);
+        List<String> commandList = new ArrayList<>(command.length);
         for (String arg : command)
-            this.command.add(arg);
+            commandList.add(arg);
+        COMMAND.setRelease(this, commandList);
     }
 
     /**
      * Sets this process builder's operating system program and
      * arguments.  This method does <i>not</i> make a copy of the

@@ -241,11 +244,11 @@
      * @return this process builder
      */
     public ProcessBuilder command(List<String> command) {
         if (command == null)
             throw new NullPointerException();
-        this.command = command;
+        COMMAND.setRelease(this, command);
         return this;
     }
 
     /**
      * Sets this process builder's operating system program and

@@ -272,11 +275,11 @@
      * process builder.
      *
      * @return this process builder's program and its arguments
      */
     public List<String> command() {
-        return command;
+        return (List<String>) COMMAND.getAcquire(this);
     }
 
     /**
      * Returns a string map view of this process builder's environment.
      *

@@ -348,16 +351,19 @@
     public Map<String,String> environment() {
         SecurityManager security = System.getSecurityManager();
         if (security != null)
             security.checkPermission(new RuntimePermission("getenv.*"));
 
-        if (environment == null)
-            environment = ProcessEnvironment.environment();
-
-        assert environment != null;
-
+        // Multiple threads may call this method without synchronization
+        for (;;) {
+            Map<String,String> environment = (Map<String,String>)
+                ENVIRONMENT.getAcquire(this);
+            if (environment != null)
         return environment;
+            ENVIRONMENT.compareAndSet(this, null,
+                                      ProcessEnvironment.environment());
+        }
     }
 
     // Only for use by Runtime.exec(...envp...)
     ProcessBuilder environment(String[] envp) {
         assert environment == null;

@@ -1296,6 +1302,21 @@
             });
             throw ex;
         }
         return processes;
     }
+
+    // VarHandle mechanics
+    private static final VarHandle COMMAND;
+    private static final VarHandle ENVIRONMENT;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            COMMAND = l.findVarHandle(
+                    ProcessBuilder.class, "command", List.class);
+            ENVIRONMENT = l.findVarHandle(
+                    ProcessBuilder.class, "environment", Map.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
 }
< prev index next >