001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Serguei S.Zapreyev
019: * @version $Revision: 1.1.2.2.4.5 $
020: *
021: */
022:
023: /**
024: * ###############################################################################
025: * ###############################################################################
026: * TODO LIST:
027: * 1. Provide correct processing the case if process isn't started because of some
028: * reason
029: * 2. Clean and develop the native support
030: * 3. Think of the default/undefault buffering
031: * 3. Runtime.SubProcess.SubInputStream.read(b, off, len) and
032: * Runtime.SubProcess.SubErrorStream.read(b, off, len) should be effectively
033: * reimplemented on the native side.
034: * ###############################################################################
035: * ###############################################################################
036: */package java.lang;
037:
038: import java.util.StringTokenizer;
039: import java.io.BufferedInputStream;
040: import java.io.BufferedOutputStream;
041: import java.io.File;
042: import java.io.InputStream;
043: import java.io.OutputStream;
044: import java.io.IOException;
045: import java.lang.UnsatisfiedLinkError;
046: import java.lang.VMExecutionEngine;
047: import java.lang.VMMemoryManager;
048: import java.util.ArrayList;
049: import org.apache.harmony.vm.VMStack;
050: import org.apache.harmony.kernel.vm.VM;
051: import org.apache.harmony.luni.util.DeleteOnExit;
052: import org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection;
053: import org.apache.harmony.lang.RuntimePermissionCollection;
054:
055: /**
056: * @com.intel.drl.spec_ref
057: */
058: public class Runtime {
059:
060: //--------------------------------------------------------------------------------
061: // Nested protected Runtime.SubProcess class:
062: //--------------------------------------------------------------------------------
063:
064: static final class SubProcess extends Process {
065:
066: final static class SubInputStream extends InputStream {
067:
068: long streamHandle;
069:
070: /**
071: * Constructs a new SubInputStream instance.
072: */
073: SubInputStream() {
074: this .streamHandle = -1;
075: }
076:
077: /**
078: * Reads the next byte of data from the input stream....
079: *
080: * @see int read() from InputStream
081: */
082: private final native int readInputByte0(long handle)
083: throws IOException;
084:
085: public final int read() throws IOException {
086: return readInputByte0(this .streamHandle);
087: }
088:
089: /**
090: * Returns the number of bytes that can be read (or skipped over) from
091: * this input stream without blocking by the next caller
092: * of a method for this input stream...
093: *
094: * @see int available() from InputStream
095: */
096: private final native int available0(long handle);
097:
098: public final int available() throws IOException {
099: return available0(this .streamHandle);
100: }
101:
102: /**
103: * Reads len bytes from input stream ...
104: *
105: * @see void read(byte[], int, int) from InputStream
106: */
107: public int read(byte[] b, int off, int len)
108: throws IOException {
109: if (b == null) {
110: throw new NullPointerException();
111: }
112:
113: if (off < 0 || len < 0 || off + len > b.length) {
114: throw new IndexOutOfBoundsException();
115: }
116:
117: if (len == 0) {
118: return 0;
119: }
120: int c = read();
121: if (c == -1) {
122: return -1;
123: }
124: b[off] = (byte) c;
125:
126: int i = 1;
127: for (; i < len; i++) {
128: try {
129: if (available() != 0) {
130: int r = read();
131: if (r != -1) {
132: b[off + i] = (byte) r;
133: continue;
134: }
135: return i;
136: }
137: } catch (IOException e) {
138: break; //If any subsequent call to read() results in a IOException
139: }
140: break; //but a smaller number may be read, possibly zero.
141: }
142: return i;
143: }
144:
145: /**
146: * Closes this input stream and releases any system resources associated
147: * with the stream.
148: *
149: * @see void close() from InputStream
150: */
151: private final native void close0(long handle)
152: throws IOException;
153:
154: public final synchronized void close() throws IOException {
155: if (streamHandle == -1)
156: return;
157: close0(streamHandle);
158: streamHandle = -1;
159: }
160:
161: protected void finalize() throws Throwable {
162: close();
163: }
164: }
165:
166: //--------------------------------------------------------------------------------
167: // Nested Class Runtime.SubProcess.SubOutputStream :
168: //--------------------------------------------------------------------------------
169:
170: /**
171: * Extends OutputStream class.
172: */
173: final static class SubOutputStream extends OutputStream {
174:
175: long streamHandle;
176:
177: /**
178: * Constructs a new SubOutputStream instance.
179: */
180: SubOutputStream() {
181: this .streamHandle = -1;
182: }
183:
184: /**
185: * Writes the specified byte to this output stream ...
186: *
187: * @see void write(int) from OutputStream
188: */
189: private final native void writeOutputByte0(long handle,
190: int bt);
191:
192: public final void write(int b) throws IOException {
193: writeOutputByte0(this .streamHandle, b);
194: }
195:
196: /**
197: * Writes len bytes from the specified byte array starting at
198: * offset off to this output stream ...
199: *
200: * @see void write(byte[], int, int) from OutputStream
201: */
202: private final native void writeOutputBytes0(long handle,
203: byte[] b, int off, int len);
204:
205: public final void write(byte[] b, int off, int len)
206: throws IOException {
207: if (b == null) {
208: throw new NullPointerException();
209: }
210:
211: if (off < 0 || len < 0 || off + len > b.length) {
212: throw new IndexOutOfBoundsException();
213: }
214:
215: writeOutputBytes0(this .streamHandle, b, off, len);
216: }
217:
218: /**
219: * Writes b.length bytes from the specified byte array to this output stream...
220: *
221: * @see void write(byte[]) from OutputStream
222: */
223: public final void write(byte[] b) throws IOException {
224: write(b, 0, b.length);
225: }
226:
227: /**
228: * Flushes this output stream and forces any buffered output
229: * bytes to be written out ...
230: *
231: * @see void flush() from OutputStream
232: */
233: private final native void flush0(long handle);
234:
235: public final void flush() throws IOException {
236: flush0(this .streamHandle);
237: }
238:
239: /**
240: * Closes this output stream and releases any system resources
241: * associated with this stream ...
242: *
243: * @see void close() from OutputStream
244: */
245: private final native void close0(long handle);
246:
247: public final synchronized void close() throws IOException {
248: if (streamHandle == -1)
249: return;
250: close0(streamHandle);
251: streamHandle = -1;
252: }
253:
254: protected void finalize() throws Throwable {
255: close();
256: }
257: }
258:
259: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
260: ///////////////////////////////////// Runtime.SubProcess BODY //////////////////////////////////
261: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
262:
263: private int processHandle;
264: private int processExitCode;
265: private OutputStream os;
266: private InputStream is;
267: private InputStream es;
268:
269: /**
270: * An application cannot create its own instance of this class.
271: */
272: protected SubProcess() {
273: this .processHandle = -1;
274: this .processExitCode = 0;
275: this .os = null;
276: this .is = null;
277: this .es = null;
278: }
279:
280: private final native void close0(int handle);
281:
282: protected void finalize() throws Throwable {
283: if (processHandle != -1)
284: close0(this .processHandle);
285: }
286:
287: /**
288: * @see OutputStream.getOutputStream() from Process
289: */
290: public final OutputStream getOutputStream() {
291: return os;
292: }
293:
294: /**
295: * @see InputStream.getInputStream() from Process
296: */
297: public final InputStream getInputStream() {
298: return is;
299: }
300:
301: /**
302: * @see InputStream getErrorStream() from Process
303: */
304: public final InputStream getErrorStream() {
305: return es;
306: }
307:
308: private final native boolean getState0(int this ProcessHandle);
309:
310: private final native void createProcess0(Object[] cmdarray,
311: Object[] envp, String dir, long[] ia);
312:
313: protected final void execVM(String[] cmdarray, String[] envp,
314: String dir) throws IOException {
315: // Do all java heap allocation first, in order to throw OutOfMemory
316: // exception early, before we have actually executed the process.
317: // Otherwise we should do somewhat complicated cleanup.
318: SubProcess.SubOutputStream os1 = new SubProcess.SubOutputStream();
319: SubProcess.SubInputStream is1 = new SubProcess.SubInputStream();
320: SubProcess.SubInputStream es1 = new SubProcess.SubInputStream();
321:
322: long[] la = new long[4];
323: createProcess0(cmdarray, envp, dir, la);
324: if (la[0] == 0) {
325: String cmd = null;
326: for (int i = 0; i < cmdarray.length; i++) {
327: if (i == 0) {
328: cmd = "\"" + cmdarray[i] + "\"";
329: } else {
330: cmd = cmd + " " + cmdarray[i];
331: }
332: }
333: throw new IOException(
334: "The creation of the Process has just failed: "
335: + cmd);
336: }
337: this .processHandle = (int) la[0];
338: os1.streamHandle = la[1];
339: is1.streamHandle = la[2];
340: es1.streamHandle = la[3];
341: os = new BufferedOutputStream(os1);
342: is = new BufferedInputStream(is1);
343: es = new BufferedInputStream(es1);
344: }
345:
346: /**
347: * @seeint waitFor() from Process
348: */
349: public int waitFor() throws InterruptedException {
350: while (true) {
351: synchronized (this ) {
352: if (getState0(processHandle))
353: break;
354: }
355: Thread.sleep(50);
356: }
357:
358: return processExitCode;
359: }
360:
361: /**
362: * @see int exitValue() from Process
363: */
364: public synchronized int exitValue()
365: throws IllegalThreadStateException {
366: if (!getState0(processHandle)) {
367: throw new IllegalThreadStateException(
368: "process has not exited");
369: }
370:
371: return processExitCode;
372: }
373:
374: /**
375: * @see void destroy() from Process
376: */
377: private final native void destroy0(int this ProcessHandle);
378:
379: public synchronized final void destroy() {
380: destroy0(processHandle);
381: }
382:
383: }
384:
385: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
386: ////////////////////////////////////////// RUNTIME BODY ////////////////////////////////////////
387: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
388:
389: /**
390: * "Every Java application has a single instance of class Runtime ..."
391: */
392: private static Runtime this ApplicationRuntime = new Runtime();
393:
394: private static ArrayList<Thread> hooksList = new ArrayList<Thread>();
395:
396: /**
397: * 0 - normal work
398: * 1 - being shutdown sequence running
399: * 2 - being finalizing
400: */
401: private static int VMState = 0;
402:
403: static boolean finalizeOnExit = false;
404:
405: /**
406: * An application cannot create its own instance of this class.
407: */
408: private Runtime() {
409: }
410:
411: /**
412: * @com.intel.drl.spec_ref
413: */
414: public static Runtime getRuntime() {
415: return this ApplicationRuntime;
416: }
417:
418: void execShutdownSequence() {
419: synchronized (hooksList) {
420: if (VMState > 0) {
421: return;
422: }
423: try {
424: // Phase1: Execute all registered hooks.
425: VMState = 1;
426: for (Thread hook : hooksList) {
427: hook.start();
428: }
429:
430: for (Thread hook : hooksList) {
431: while (true) {
432: try {
433: hook.join();
434: break;
435: } catch (InterruptedException e) {
436: continue;
437: }
438: }
439: }
440: // Phase2: Execute all finalizers if nessesary.
441: VMState = 2;
442: FinalizerThread.shutdown(finalizeOnExit);
443:
444: // Close connections.
445: if (VM.closeJars) {
446: JarURLConnection.closeCachedFiles();
447: }
448:
449: // Delete files.
450: if (VM.deleteOnExit) {
451: DeleteOnExit.deleteOnExit();
452: }
453: } catch (Throwable e) {
454: // just catch all exceptions
455: }
456: }
457: }
458:
459: /**
460: * @com.intel.drl.spec_ref
461: */
462: public void exit(int status) throws SecurityException {
463: SecurityManager sm = System.getSecurityManager();
464: if (sm != null) {
465: sm.checkExit(status);
466: }
467: // Halt the VM if it is running finalizers.
468: if (VMState == 2 && finalizeOnExit == true && status != 0) {
469: halt(status);
470: }
471:
472: execShutdownSequence();
473: // No need to invoke finalizers one more time.
474: // vvvvv
475: VMExecutionEngine.exit(status, false);
476: }
477:
478: /**
479: * @com.intel.drl.spec_ref
480: */
481: public void addShutdownHook(Thread hook) {
482: SecurityManager sm = System.getSecurityManager();
483: if (sm != null) {
484: sm
485: .checkPermission(RuntimePermissionCollection.SHUTDOWN_HOOKS_PERMISSION);
486: }
487: // Check hook for null
488: if (hook == null)
489: throw new NullPointerException("null is not allowed here");
490:
491: if (hook.getState() != Thread.State.NEW) {
492: throw new IllegalArgumentException();
493: }
494: if (VMState > 0) {
495: throw new IllegalStateException();
496: }
497: synchronized (hooksList) {
498: if (hooksList.contains(hook)) {
499: throw new IllegalArgumentException();
500: }
501: hooksList.add(hook);
502: }
503: }
504:
505: /**
506: * @com.intel.drl.spec_ref
507: */
508: public boolean removeShutdownHook(Thread hook) {
509: SecurityManager sm = System.getSecurityManager();
510: if (sm != null) {
511: sm
512: .checkPermission(RuntimePermissionCollection.SHUTDOWN_HOOKS_PERMISSION);
513: }
514: // Check hook for null
515: if (hook == null)
516: throw new NullPointerException("null is not allowed here");
517:
518: if (VMState > 0) {
519: throw new IllegalStateException();
520: }
521: synchronized (hooksList) {
522: return hooksList.remove(hook);
523: }
524: }
525:
526: /**
527: * @com.intel.drl.spec_ref
528: */
529: public void halt(int status) {
530: SecurityManager sm = System.getSecurityManager();
531:
532: if (sm != null) {
533: sm.checkExit(status);
534: }
535: VMExecutionEngine.exit(status, false);
536: }
537:
538: /**
539: * @com.intel.drl.spec_ref
540: * @deprecated
541: */
542: public static void runFinalizersOnExit(boolean value) {
543: SecurityManager sm = System.getSecurityManager();
544: if (sm != null) {
545: sm.checkExit(0);
546: }
547: synchronized (hooksList) {
548: finalizeOnExit = value;
549: }
550: }
551:
552: /**
553: * @com.intel.drl.spec_ref
554: */
555: public Process exec(String command) throws IOException {
556: return exec(command, null, null);
557: }
558:
559: /**
560: * @com.intel.drl.spec_ref
561: */
562: public Process exec(String cmd, String[] envp) throws IOException {
563: return exec(cmd, envp, null);
564: }
565:
566: /**
567: * @com.intel.drl.spec_ref
568: */
569: public Process exec(String command, String[] envp, File dir)
570: throws IOException {
571: if (command == null) {
572: throw new NullPointerException();
573: }
574: if (command.length() == 0) {
575: throw new IllegalArgumentException();
576: }
577: if (envp != null) {
578: if (envp.length != 0) {
579: for (int i = 0; i < envp.length; i++) {
580: if (envp[i] == null) {
581: throw new NullPointerException(
582: "An element of envp shouldn't be empty.");
583: }
584: }
585: } else {
586: envp = null;
587: }
588: }
589:
590: StringTokenizer st = new StringTokenizer(command);
591: String[] cmdarray = new String[st.countTokens()];
592: int i = 0;
593:
594: while (st.hasMoreTokens()) {
595: cmdarray[i++] = st.nextToken();
596:
597: }
598:
599: return exec(cmdarray, envp, dir);
600:
601: }
602:
603: /**
604: * @com.intel.drl.spec_ref
605: */
606: public Process exec(String[] cmdarray) throws IOException {
607: return exec(cmdarray, null, null);
608:
609: }
610:
611: /**
612: * @com.intel.drl.spec_ref
613: */
614: public Process exec(String[] cmdarray, String[] envp)
615: throws IOException, NullPointerException,
616: IndexOutOfBoundsException, SecurityException {
617: return exec(cmdarray, envp, null);
618:
619: }
620:
621: /**
622: * @com.intel.drl.spec_ref
623: */
624: public Process exec(String[] cmdarray, String[] envp, File dir)
625: throws IOException {
626: SecurityManager currentSecurity = System.getSecurityManager();
627:
628: if (currentSecurity != null) {
629: currentSecurity.checkExec(cmdarray[0]);
630: }
631:
632: if (cmdarray == null) {
633: throw new NullPointerException(
634: "Command argument shouldn't be empty.");
635: }
636: if (cmdarray.length == 0) {
637: throw new IndexOutOfBoundsException();
638: }
639: for (int i = 0; i < cmdarray.length; i++) {
640: if (cmdarray[i] == null) {
641: throw new NullPointerException(
642: "An element of cmdarray shouldn't be empty.");
643: }
644: }
645: if (envp != null) {
646: if (envp.length != 0) {
647: for (int i = 0; i < envp.length; i++) {
648: if (envp[i] == null) {
649: throw new NullPointerException(
650: "An element of envp shouldn't be empty.");
651: }
652: }
653: } else {
654: envp = null;
655: }
656: }
657:
658: String dirPathName = (dir != null ? dir.getPath() : null);
659:
660: SubProcess sp = new SubProcess();
661:
662: sp.execVM(cmdarray, envp, dirPathName);
663:
664: return sp;
665:
666: }
667:
668: /**
669: * @com.intel.drl.spec_ref
670: */
671: public int availableProcessors() {
672: return VMExecutionEngine.getAvailableProcessors();
673: }
674:
675: /**
676: * @com.intel.drl.spec_ref
677: */
678: public long freeMemory() {
679: return VMMemoryManager.getFreeMemory();
680: }
681:
682: /**
683: * @com.intel.drl.spec_ref
684: */
685: public long totalMemory() {
686: return VMMemoryManager.getTotalMemory();
687: }
688:
689: /**
690: * @com.intel.drl.spec_ref
691: */
692: public long maxMemory() {
693: return VMMemoryManager.getMaxMemory();
694: }
695:
696: /**
697: * @com.intel.drl.spec_ref
698: */
699: public void gc() {
700: VMMemoryManager.runGC();
701: }
702:
703: /**
704: * @com.intel.drl.spec_ref
705: */
706: public void runFinalization() {
707: VMMemoryManager.runFinalization();
708: }
709:
710: /**
711: * @com.intel.drl.spec_ref
712: */
713: public void traceInstructions(boolean on) {
714: VMExecutionEngine.traceInstructions(on);
715: }
716:
717: /**
718: * @com.intel.drl.spec_ref
719: */
720: public void traceMethodCalls(boolean on) {
721: VMExecutionEngine.traceMethodCalls(on);
722: }
723:
724: /**
725: * @com.intel.drl.spec_ref
726: */
727: public void load(String filename) throws SecurityException,
728: UnsatisfiedLinkError {
729: load0(filename, VMClassRegistry.getClassLoader(VMStack
730: .getCallerClass(0)), true);
731: }
732:
733: void load0(String filename, ClassLoader cL, boolean check)
734: throws SecurityException, UnsatisfiedLinkError {
735: if (check) {
736: if (filename == null) {
737: throw new NullPointerException();
738: }
739:
740: SecurityManager currentSecurity = System
741: .getSecurityManager();
742:
743: if (currentSecurity != null) {
744: currentSecurity.checkLink(filename);
745: }
746: }
747: VMClassRegistry.loadLibrary(filename, cL); // Should throw UnsatisfiedLinkError if needs.
748: }
749:
750: /**
751: * @com.intel.drl.spec_ref
752: */
753: public void loadLibrary(String libname) throws SecurityException,
754: UnsatisfiedLinkError {
755: loadLibrary0(libname, VMClassRegistry.getClassLoader(VMStack
756: .getCallerClass(0)), true);
757: }
758:
759: void loadLibrary0(String libname, ClassLoader cL, boolean check)
760: throws SecurityException, UnsatisfiedLinkError {
761: if (check) {
762: if (libname == null) {
763: throw new NullPointerException();
764: }
765:
766: SecurityManager currentSecurity = System
767: .getSecurityManager();
768:
769: if (currentSecurity != null) {
770: currentSecurity.checkLink(libname);
771: }
772: }
773:
774: String libFullName = null;
775:
776: if (cL != null) {
777: libFullName = cL.findLibrary(libname);
778: }
779: if (libFullName == null) {
780: String allPaths = null;
781:
782: //XXX: should we think hard about security policy for this block?:
783: String jlp = System.getProperty("java.library.path");
784: String vblp = System.getProperty("vm.boot.library.path");
785: String udp = System.getProperty("user.dir");
786: String pathSeparator = System.getProperty("path.separator");
787: String fileSeparator = System.getProperty("file.separator");
788: allPaths = (jlp != null ? jlp : "")
789: + (vblp != null ? pathSeparator + vblp : "")
790: + (udp != null ? pathSeparator + udp : "");
791:
792: if (allPaths.length() == 0) {
793: throw new UnsatisfiedLinkError(
794: "Can not find the library: " + libname);
795: }
796:
797: //String[] paths = allPaths.split(pathSeparator);
798: String[] paths;
799: {
800: ArrayList<String> res = new ArrayList<String>();
801: int curPos = 0;
802: int l = pathSeparator.length();
803: int i = allPaths.indexOf(pathSeparator);
804: int in = 0;
805: while (i != -1) {
806: String s = allPaths.substring(curPos, i);
807: res.add(s);
808: in++;
809: curPos = i + l;
810: i = allPaths.indexOf(pathSeparator, curPos);
811: }
812:
813: if (curPos <= allPaths.length()) {
814: String s = allPaths.substring(curPos, allPaths
815: .length());
816: in++;
817: res.add(s);
818: }
819:
820: paths = (String[]) res.toArray(new String[in]);
821: }
822:
823: libname = System.mapLibraryName(libname);
824: for (int i = 0; i < paths.length; i++) {
825: if (paths[i] == null) {
826: continue;
827: }
828: libFullName = paths[i] + fileSeparator + libname;
829: try {
830: this .load0(libFullName, cL, false);
831: return;
832: } catch (UnsatisfiedLinkError e) {
833: }
834: }
835: } else {
836: this .load0(libFullName, cL, false);
837: return;
838: }
839: throw new UnsatisfiedLinkError("Can not find the library: "
840: + libname);
841: }
842:
843: /**
844: * @com.intel.drl.spec_ref
845: * @deprecated
846: */
847: public InputStream getLocalizedInputStream(InputStream in) {
848: //XXX: return new BufferedInputStream( (InputStream) (Object) new InputStreamReader( in ) );
849: return in;
850: }
851:
852: /**
853: * @com.intel.drl.spec_ref
854: * @deprecated
855: */
856: public OutputStream getLocalizedOutputStream(OutputStream out) {
857: //XXX: return new BufferedOutputStream( (OutputStream) (Object) new OutputStreamWriter( out ) );
858: return out;
859: }
860: }
|