1 /* Runtime.java -- access to the VM process 2 Copyright (C) 1998, 2002, 2003, 2004, 2005, 2006 Free Software Foundation 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.lang; 40 41 import gnu.classpath.SystemProperties; 42 43 import java.io.File; 44 import java.io.IOException; 45 import java.io.InputStream; 46 import java.io.OutputStream; 47 import java.util.HashSet; 48 import java.util.Iterator; 49 import java.util.Set; 50 import java.util.StringTokenizer; 51 52 /** 53 * Runtime represents the Virtual Machine. 54 * 55 * @author John Keiser 56 * @author Eric Blake (ebb9@email.byu.edu) 57 * @author Jeroen Frijters 58 */ 59 // No idea why this class isn't final, since you can't build a subclass! 60 public class Runtime 61 { 62 /** 63 * The library path, to search when loading libraries. We can also safely use 64 * this as a lock for synchronization. 65 */ 66 private final String[] libpath; 67 68 static 69 { init()70 init(); 71 } 72 73 /** 74 * The thread that started the exit sequence. Access to this field must 75 * be thread-safe; lock on libpath to avoid deadlock with user code. 76 * <code>runFinalization()</code> may want to look at this to see if ALL 77 * finalizers should be run, because the virtual machine is about to halt. 78 */ 79 private Thread exitSequence; 80 81 /** 82 * All shutdown hooks. This is initialized lazily, and set to null once all 83 * shutdown hooks have run. Access to this field must be thread-safe; lock 84 * on libpath to avoid deadlock with user code. 85 */ 86 private Set shutdownHooks; 87 88 /** True if we should finalize on exit. */ 89 private boolean finalizeOnExit; 90 91 /** 92 * The one and only runtime instance. 93 */ 94 private static final Runtime current = new Runtime(); 95 96 /** 97 * Not instantiable by a user, this should only create one instance. 98 */ Runtime()99 private Runtime() 100 { 101 if (current != null) 102 throw new InternalError("Attempt to recreate Runtime"); 103 104 // We don't use libpath in the libgcj implementation. We still 105 // set it to something to allow the various synchronizations to 106 // work. 107 libpath = new String[0]; 108 } 109 110 /** 111 * Get the current Runtime object for this JVM. This is necessary to access 112 * the many instance methods of this class. 113 * 114 * @return the current Runtime object 115 */ getRuntime()116 public static Runtime getRuntime() 117 { 118 return current; 119 } 120 121 /** 122 * Exit the Java runtime. This method will either throw a SecurityException 123 * or it will never return. The status code is returned to the system; often 124 * a non-zero status code indicates an abnormal exit. Of course, there is a 125 * security check, <code>checkExit(status)</code>. 126 * 127 * <p>First, all shutdown hooks are run, in unspecified order, and 128 * concurrently. Next, if finalization on exit has been enabled, all pending 129 * finalizers are run. Finally, the system calls <code>halt</code>.</p> 130 * 131 * <p>If this is run a second time after shutdown has already started, there 132 * are two actions. If shutdown hooks are still executing, it blocks 133 * indefinitely. Otherwise, if the status is nonzero it halts immediately; 134 * if it is zero, it blocks indefinitely. This is typically called by 135 * <code>System.exit</code>.</p> 136 * 137 * @param status the status to exit with 138 * @throws SecurityException if permission is denied 139 * @see #addShutdownHook(Thread) 140 * @see #runFinalizersOnExit(boolean) 141 * @see #runFinalization() 142 * @see #halt(int) 143 */ exit(int status)144 public void exit(int status) 145 { 146 SecurityManager sm = SecurityManager.current; // Be thread-safe! 147 if (sm != null) 148 sm.checkExit(status); 149 exitNoChecks(status); 150 } 151 152 // Accessor to avoid adding a vtable slot. exitNoChecksAccessor(int status)153 static void exitNoChecksAccessor(int status) 154 { 155 current.exitNoChecks(status); 156 } 157 158 // Private since we can't add a vtable slot in 4.1.x. exitNoChecks(int status)159 private void exitNoChecks(int status) 160 { 161 if (runShutdownHooks()) 162 exitInternal(status); 163 164 // Someone else already called runShutdownHooks(). 165 // Make sure we are not/no longer in the shutdownHooks set. 166 // And wait till the thread that is calling runShutdownHooks() finishes. 167 synchronized (libpath) 168 { 169 if (shutdownHooks != null) 170 { 171 shutdownHooks.remove(Thread.currentThread()); 172 // Interrupt the exit sequence thread, in case it was waiting 173 // inside a join on our thread. 174 exitSequence.interrupt(); 175 // Shutdown hooks are still running, so we clear status to 176 // make sure we don't halt. 177 status = 0; 178 } 179 } 180 181 // If exit() is called again after the shutdown hooks have run, but 182 // while finalization for exit is going on and the status is non-zero 183 // we halt immediately. 184 if (status != 0) 185 exitInternal(status); 186 187 while (true) 188 try 189 { 190 exitSequence.join(); 191 } 192 catch (InterruptedException e) 193 { 194 // Ignore, we've suspended indefinitely to let all shutdown 195 // hooks complete, and to let any non-zero exits through, because 196 // this is a duplicate call to exit(0). 197 } 198 } 199 200 /** 201 * On first invocation, run all the shutdown hooks and return true. 202 * Any subsequent invocations will simply return false. 203 * Note that it is package accessible so that VMRuntime can call it 204 * when VM exit is not triggered by a call to Runtime.exit(). 205 * 206 * @return was the current thread the first one to call this method? 207 */ runShutdownHooks()208 boolean runShutdownHooks() 209 { 210 boolean first = false; 211 synchronized (libpath) // Synch on libpath, not this, to avoid deadlock. 212 { 213 if (exitSequence == null) 214 { 215 first = true; 216 exitSequence = Thread.currentThread(); 217 if (shutdownHooks != null) 218 { 219 Iterator i = shutdownHooks.iterator(); 220 while (i.hasNext()) // Start all shutdown hooks. 221 try 222 { 223 ((Thread) i.next()).start(); 224 } 225 catch (IllegalThreadStateException e) 226 { 227 i.remove(); 228 } 229 } 230 } 231 } 232 if (first) 233 { 234 if (shutdownHooks != null) 235 { 236 // Check progress of all shutdown hooks. As a hook completes, 237 // remove it from the set. If a hook calls exit, it removes 238 // itself from the set, then waits indefinitely on the 239 // exitSequence thread. Once the set is empty, set it to null to 240 // signal all finalizer threads that halt may be called. 241 while (true) 242 { 243 Thread[] hooks; 244 synchronized (libpath) 245 { 246 hooks = new Thread[shutdownHooks.size()]; 247 shutdownHooks.toArray(hooks); 248 } 249 if (hooks.length == 0) 250 break; 251 for (int i = 0; i < hooks.length; i++) 252 { 253 try 254 { 255 synchronized (libpath) 256 { 257 if (!shutdownHooks.contains(hooks[i])) 258 continue; 259 } 260 hooks[i].join(); 261 synchronized (libpath) 262 { 263 shutdownHooks.remove(hooks[i]); 264 } 265 } 266 catch (InterruptedException x) 267 { 268 // continue waiting on the next thread 269 } 270 } 271 } 272 synchronized (libpath) 273 { 274 shutdownHooks = null; 275 } 276 } 277 // Run finalization on all finalizable objects (even if they are 278 // still reachable). 279 runFinalizationForExit(); 280 } 281 return first; 282 } 283 284 /** 285 * Register a new shutdown hook. This is invoked when the program exits 286 * normally (because all non-daemon threads ended, or because 287 * <code>System.exit</code> was invoked), or when the user terminates 288 * the virtual machine (such as by typing ^C, or logging off). There is 289 * a security check to add hooks, 290 * <code>RuntimePermission("shutdownHooks")</code>. 291 * 292 * <p>The hook must be an initialized, but unstarted Thread. The threads 293 * are run concurrently, and started in an arbitrary order; and user 294 * threads or daemons may still be running. Once shutdown hooks have 295 * started, they must all complete, or else you must use <code>halt</code>, 296 * to actually finish the shutdown sequence. Attempts to modify hooks 297 * after shutdown has started result in IllegalStateExceptions.</p> 298 * 299 * <p>It is imperative that you code shutdown hooks defensively, as you 300 * do not want to deadlock, and have no idea what other hooks will be 301 * running concurrently. It is also a good idea to finish quickly, as the 302 * virtual machine really wants to shut down!</p> 303 * 304 * <p>There are no guarantees that such hooks will run, as there are ways 305 * to forcibly kill a process. But in such a drastic case, shutdown hooks 306 * would do little for you in the first place.</p> 307 * 308 * @param hook an initialized, unstarted Thread 309 * @throws IllegalArgumentException if the hook is already registered or run 310 * @throws IllegalStateException if the virtual machine is already in 311 * the shutdown sequence 312 * @throws SecurityException if permission is denied 313 * @since 1.3 314 * @see #removeShutdownHook(Thread) 315 * @see #exit(int) 316 * @see #halt(int) 317 */ addShutdownHook(Thread hook)318 public void addShutdownHook(Thread hook) 319 { 320 SecurityManager sm = SecurityManager.current; // Be thread-safe! 321 if (sm != null) 322 sm.checkPermission(new RuntimePermission("shutdownHooks")); 323 if (hook.isAlive() || hook.getThreadGroup() == null) 324 throw new IllegalArgumentException("The hook thread " + hook + " must not have been already run or started"); 325 synchronized (libpath) 326 { 327 if (exitSequence != null) 328 throw new IllegalStateException("The Virtual Machine is exiting. It is not possible anymore to add any hooks"); 329 if (shutdownHooks == null) 330 shutdownHooks = new HashSet(); // Lazy initialization. 331 if (! shutdownHooks.add(hook)) 332 throw new IllegalArgumentException(hook.toString() + " had already been inserted"); 333 } 334 } 335 336 /** 337 * De-register a shutdown hook. As when you registered it, there is a 338 * security check to remove hooks, 339 * <code>RuntimePermission("shutdownHooks")</code>. 340 * 341 * @param hook the hook to remove 342 * @return true if the hook was successfully removed, false if it was not 343 * registered in the first place 344 * @throws IllegalStateException if the virtual machine is already in 345 * the shutdown sequence 346 * @throws SecurityException if permission is denied 347 * @since 1.3 348 * @see #addShutdownHook(Thread) 349 * @see #exit(int) 350 * @see #halt(int) 351 */ removeShutdownHook(Thread hook)352 public boolean removeShutdownHook(Thread hook) 353 { 354 SecurityManager sm = SecurityManager.current; // Be thread-safe! 355 if (sm != null) 356 sm.checkPermission(new RuntimePermission("shutdownHooks")); 357 synchronized (libpath) 358 { 359 if (exitSequence != null) 360 throw new IllegalStateException(); 361 if (shutdownHooks != null) 362 return shutdownHooks.remove(hook); 363 } 364 return false; 365 } 366 367 /** 368 * Forcibly terminate the virtual machine. This call never returns. It is 369 * much more severe than <code>exit</code>, as it bypasses all shutdown 370 * hooks and initializers. Use caution in calling this! Of course, there is 371 * a security check, <code>checkExit(status)</code>. 372 * 373 * @param status the status to exit with 374 * @throws SecurityException if permission is denied 375 * @since 1.3 376 * @see #exit(int) 377 * @see #addShutdownHook(Thread) 378 */ halt(int status)379 public void halt(int status) 380 { 381 SecurityManager sm = SecurityManager.current; // Be thread-safe! 382 if (sm != null) 383 sm.checkExit(status); 384 exitInternal(status); 385 } 386 387 /** 388 * Tell the VM to run the finalize() method on every single Object before 389 * it exits. Note that the JVM may still exit abnormally and not perform 390 * this, so you still don't have a guarantee. And besides that, this is 391 * inherently unsafe in multi-threaded code, as it may result in deadlock 392 * as multiple threads compete to manipulate objects. This value defaults to 393 * <code>false</code>. There is a security check, <code>checkExit(0)</code>. 394 * 395 * @param finalizeOnExit whether to finalize all Objects on exit 396 * @throws SecurityException if permission is denied 397 * @see #exit(int) 398 * @see #gc() 399 * @since 1.1 400 * @deprecated never rely on finalizers to do a clean, thread-safe, 401 * mop-up from your code 402 */ runFinalizersOnExit(boolean finalizeOnExit)403 public static void runFinalizersOnExit(boolean finalizeOnExit) 404 { 405 SecurityManager sm = SecurityManager.current; // Be thread-safe! 406 if (sm != null) 407 sm.checkExit(0); 408 current.finalizeOnExit = finalizeOnExit; 409 } 410 411 /** 412 * Create a new subprocess with the specified command line. Calls 413 * <code>exec(cmdline, null, null)</code>. A security check is performed, 414 * <code>checkExec</code>. 415 * 416 * @param cmdline the command to call 417 * @return the Process object 418 * @throws SecurityException if permission is denied 419 * @throws IOException if an I/O error occurs 420 * @throws NullPointerException if cmdline is null 421 * @throws IndexOutOfBoundsException if cmdline is "" 422 */ exec(String cmdline)423 public Process exec(String cmdline) throws IOException 424 { 425 return exec(cmdline, null, null); 426 } 427 428 /** 429 * Create a new subprocess with the specified command line and environment. 430 * If the environment is null, the process inherits the environment of 431 * this process. Calls <code>exec(cmdline, env, null)</code>. A security 432 * check is performed, <code>checkExec</code>. 433 * 434 * @param cmdline the command to call 435 * @param env the environment to use, in the format name=value 436 * @return the Process object 437 * @throws SecurityException if permission is denied 438 * @throws IOException if an I/O error occurs 439 * @throws NullPointerException if cmdline is null, or env has null entries 440 * @throws IndexOutOfBoundsException if cmdline is "" 441 */ exec(String cmdline, String[] env)442 public Process exec(String cmdline, String[] env) throws IOException 443 { 444 return exec(cmdline, env, null); 445 } 446 447 /** 448 * Create a new subprocess with the specified command line, environment, and 449 * working directory. If the environment is null, the process inherits the 450 * environment of this process. If the directory is null, the process uses 451 * the current working directory. This splits cmdline into an array, using 452 * the default StringTokenizer, then calls 453 * <code>exec(cmdArray, env, dir)</code>. A security check is performed, 454 * <code>checkExec</code>. 455 * 456 * @param cmdline the command to call 457 * @param env the environment to use, in the format name=value 458 * @param dir the working directory to use 459 * @return the Process object 460 * @throws SecurityException if permission is denied 461 * @throws IOException if an I/O error occurs 462 * @throws NullPointerException if cmdline is null, or env has null entries 463 * @throws IndexOutOfBoundsException if cmdline is "" 464 * @since 1.3 465 */ exec(String cmdline, String[] env, File dir)466 public Process exec(String cmdline, String[] env, File dir) 467 throws IOException 468 { 469 StringTokenizer t = new StringTokenizer(cmdline); 470 String[] cmd = new String[t.countTokens()]; 471 for (int i = 0; i < cmd.length; i++) 472 cmd[i] = t.nextToken(); 473 return exec(cmd, env, dir); 474 } 475 476 /** 477 * Create a new subprocess with the specified command line, already 478 * tokenized. Calls <code>exec(cmd, null, null)</code>. A security check 479 * is performed, <code>checkExec</code>. 480 * 481 * @param cmd the command to call 482 * @return the Process object 483 * @throws SecurityException if permission is denied 484 * @throws IOException if an I/O error occurs 485 * @throws NullPointerException if cmd is null, or has null entries 486 * @throws IndexOutOfBoundsException if cmd is length 0 487 */ exec(String[] cmd)488 public Process exec(String[] cmd) throws IOException 489 { 490 return exec(cmd, null, null); 491 } 492 493 /** 494 * Create a new subprocess with the specified command line, already 495 * tokenized, and specified environment. If the environment is null, the 496 * process inherits the environment of this process. Calls 497 * <code>exec(cmd, env, null)</code>. A security check is performed, 498 * <code>checkExec</code>. 499 * 500 * @param cmd the command to call 501 * @param env the environment to use, in the format name=value 502 * @return the Process object 503 * @throws SecurityException if permission is denied 504 * @throws IOException if an I/O error occurs 505 * @throws NullPointerException if cmd is null, or cmd or env has null 506 * entries 507 * @throws IndexOutOfBoundsException if cmd is length 0 508 */ exec(String[] cmd, String[] env)509 public Process exec(String[] cmd, String[] env) throws IOException 510 { 511 return exec(cmd, env, null); 512 } 513 514 /** 515 * Create a new subprocess with the specified command line, already 516 * tokenized, and the specified environment and working directory. If the 517 * environment is null, the process inherits the environment of this 518 * process. If the directory is null, the process uses the current working 519 * directory. A security check is performed, <code>checkExec</code>. 520 * 521 * @param cmd the command to call 522 * @param env the environment to use, in the format name=value 523 * @param dir the working directory to use 524 * @return the Process object 525 * @throws SecurityException if permission is denied 526 * @throws IOException if an I/O error occurs 527 * @throws NullPointerException if cmd is null, or cmd or env has null 528 * entries 529 * @throws IndexOutOfBoundsException if cmd is length 0 530 * @since 1.3 531 */ exec(String[] cmd, String[] env, File dir)532 public Process exec(String[] cmd, String[] env, File dir) 533 throws IOException 534 { 535 SecurityManager sm = SecurityManager.current; // Be thread-safe! 536 if (sm != null) 537 sm.checkExec(cmd[0]); 538 return execInternal(cmd, env, dir); 539 } 540 541 /** 542 * Returns the number of available processors currently available to the 543 * virtual machine. This number may change over time; so a multi-processor 544 * program want to poll this to determine maximal resource usage. 545 * 546 * @return the number of processors available, at least 1 547 */ availableProcessors()548 public native int availableProcessors(); 549 550 /** 551 * Find out how much memory is still free for allocating Objects on the heap. 552 * 553 * @return the number of bytes of free memory for more Objects 554 */ freeMemory()555 public native long freeMemory(); 556 557 /** 558 * Find out how much memory total is available on the heap for allocating 559 * Objects. 560 * 561 * @return the total number of bytes of memory for Objects 562 */ totalMemory()563 public native long totalMemory(); 564 565 /** 566 * Returns the maximum amount of memory the virtual machine can attempt to 567 * use. This may be <code>Long.MAX_VALUE</code> if there is no inherent 568 * limit (or if you really do have a 8 exabyte memory!). 569 * 570 * @return the maximum number of bytes the virtual machine will attempt 571 * to allocate 572 */ maxMemory()573 public native long maxMemory(); 574 575 /** 576 * Run the garbage collector. This method is more of a suggestion than 577 * anything. All this method guarantees is that the garbage collector will 578 * have "done its best" by the time it returns. Notice that garbage 579 * collection takes place even without calling this method. 580 */ gc()581 public native void gc(); 582 583 /** 584 * Run finalization on all Objects that are waiting to be finalized. Again, 585 * a suggestion, though a stronger one than {@link #gc()}. This calls the 586 * <code>finalize</code> method of all objects waiting to be collected. 587 * 588 * @see #finalize() 589 */ runFinalization()590 public native void runFinalization(); 591 592 /** 593 * Tell the VM to trace every bytecode instruction that executes (print out 594 * a trace of it). No guarantees are made as to where it will be printed, 595 * and the VM is allowed to ignore this request. 596 * 597 * @param on whether to turn instruction tracing on 598 */ traceInstructions(boolean on)599 public native void traceInstructions(boolean on); 600 601 /** 602 * Tell the VM to trace every method call that executes (print out a trace 603 * of it). No guarantees are made as to where it will be printed, and the 604 * VM is allowed to ignore this request. 605 * 606 * @param on whether to turn method tracing on 607 */ traceMethodCalls(boolean on)608 public native void traceMethodCalls(boolean on); 609 610 /** 611 * Load a native library using the system-dependent filename. This is similar 612 * to loadLibrary, except the only name mangling done is inserting "_g" 613 * before the final ".so" if the VM was invoked by the name "java_g". There 614 * may be a security check, of <code>checkLink</code>. 615 * 616 * @param filename the file to load 617 * @throws SecurityException if permission is denied 618 * @throws UnsatisfiedLinkError if the library is not found 619 */ load(String filename)620 public void load(String filename) 621 { 622 SecurityManager sm = SecurityManager.current; // Be thread-safe! 623 if (sm != null) 624 sm.checkLink(filename); 625 _load(filename, false); 626 } 627 628 /** 629 * Load a native library using a system-independent "short name" for the 630 * library. It will be transformed to a correct filename in a 631 * system-dependent manner (for example, in Windows, "mylib" will be turned 632 * into "mylib.dll"). This is done as follows: if the context that called 633 * load has a ClassLoader cl, then <code>cl.findLibrary(libpath)</code> is 634 * used to convert the name. If that result was null, or there was no class 635 * loader, this searches each directory of the system property 636 * <code>java.library.path</code> for a file named 637 * <code>System.mapLibraryName(libname)</code>. There may be a security 638 * check, of <code>checkLink</code>. 639 * 640 * @param libname the library to load 641 * 642 * @throws SecurityException if permission is denied 643 * @throws UnsatisfiedLinkError if the library is not found 644 * 645 * @see System#mapLibraryName(String) 646 * @see ClassLoader#findLibrary(String) 647 */ loadLibrary(String libname)648 public void loadLibrary(String libname) 649 { 650 // This is different from the Classpath implementation, but I 651 // believe it is more correct. 652 SecurityManager sm = SecurityManager.current; // Be thread-safe! 653 if (sm != null) 654 sm.checkLink(libname); 655 _load(libname, true); 656 } 657 658 /** 659 * Return a localized version of this InputStream, meaning all characters 660 * are localized before they come out the other end. 661 * 662 * @param in the stream to localize 663 * @return the localized stream 664 * @deprecated <code>InputStreamReader</code> is the preferred way to read 665 * local encodings 666 */ getLocalizedInputStream(InputStream in)667 public InputStream getLocalizedInputStream(InputStream in) 668 { 669 return in; 670 } 671 672 /** 673 * Return a localized version of this OutputStream, meaning all characters 674 * are localized before they are sent to the other end. 675 * 676 * @param out the stream to localize 677 * @return the localized stream 678 * @deprecated <code>OutputStreamWriter</code> is the preferred way to write 679 * local encodings 680 */ getLocalizedOutputStream(OutputStream out)681 public OutputStream getLocalizedOutputStream(OutputStream out) 682 { 683 return out; 684 } 685 686 /** 687 * Native method that actually shuts down the virtual machine. 688 * 689 * @param status the status to end the process with 690 */ exitInternal(int status)691 native void exitInternal(int status); 692 693 /** 694 * Load a file. If it has already been loaded, do nothing. The name has 695 * already been mapped to a true filename. 696 * 697 * @param filename the file to load 698 * @param do_search True if we should search the load path for the file 699 */ _load(String filename, boolean do_search)700 native void _load(String filename, boolean do_search); 701 702 /** 703 *This is a helper function for the ClassLoader which can load 704 * compiled libraries. Returns true if library (which is just the 705 * base name -- path searching is done by this function) was loaded, 706 * false otherwise. 707 */ loadLibraryInternal(String libname)708 native boolean loadLibraryInternal(String libname); 709 710 /** 711 * A helper for Runtime static initializer which does some internal native 712 * initialization. 713 */ init()714 private static native void init (); 715 716 /** 717 * Run finalizers when exiting. 718 */ runFinalizationForExit()719 private native void runFinalizationForExit(); 720 721 /** 722 * Map a system-independent "short name" to the full file name, and append 723 * it to the path. 724 * XXX This method is being replaced by System.mapLibraryName. 725 * 726 * @param pathname the path 727 * @param libname the short version of the library name 728 * @return the full filename 729 */ nativeGetLibname(String pathname, String libname)730 static native String nativeGetLibname(String pathname, String libname); 731 732 /** 733 * Execute a process. The command line has already been tokenized, and 734 * the environment should contain name=value mappings. If directory is null, 735 * use the current working directory; otherwise start the process in that 736 * directory. 737 * 738 * @param cmd the non-null command tokens 739 * @param env the non-null environment setup 740 * @param dir the directory to use, may be null 741 * @return the newly created process 742 * @throws NullPointerException if cmd or env have null elements 743 * @throws IOException if the exec fails 744 */ execInternal(String[] cmd, String[] env, File dir)745 native Process execInternal(String[] cmd, String[] env, File dir) 746 throws IOException; 747 } // class Runtime 748