4 import java.util.TimeZone;
6 public abstract class UnixRuntime extends Runtime {
7 /** The pid of this "process" */
10 public int getPid() { return pid; }
13 private final Object waitNotification = new Object();
14 private final static int MAX_TASKS = 256;
15 private final static UnixRuntime[] tasks = new UnixRuntime[MAX_TASKS];
16 private static int addTask(UnixRuntime rt) {
18 for(int i=1;i<MAX_TASKS;i++) {
19 if(tasks[i] == null) {
28 private static void removeTask(UnixRuntime rt) {
30 for(int i=1;i<MAX_TASKS;i++)
31 if(tasks[i] == rt) { tasks[i] = null; break; }
35 public UnixRuntime(int pageSize, int totalPages, boolean allowEmptyPages) {
36 super(pageSize,totalPages,allowEmptyPages);
39 private static String posixTZ() {
40 StringBuffer sb = new StringBuffer();
41 TimeZone zone = TimeZone.getDefault();
42 int off = zone.getRawOffset() / 1000;
43 sb.append(zone.getDisplayName(false,TimeZone.SHORT));
44 if(off > 0) sb.append("-");
46 sb.append(off/3600); off = off%3600;
47 if(off > 0) sb.append(":").append(off/60); off=off%60;
48 if(off > 0) sb.append(":").append(off);
49 if(zone.useDaylightTime())
50 sb.append(zone.getDisplayName(true,TimeZone.SHORT));
54 private static boolean envHas(String key,String[] environ) {
55 for(int i=0;i<environ.length;i++)
56 if(environ[i]!=null && environ[i].startsWith(key + "=")) return true;
60 protected String[] createEnv(String[] extra) {
61 String[] defaults = new String[5];
63 if(extra == null) extra = new String[0];
64 if(!envHas("USER",extra) && getSystemProperty("user.name") != null)
65 defaults[n++] = "USER=" + getSystemProperty("user.name");
66 if(!envHas("HOME",extra) && getSystemProperty("user.name") != null)
67 defaults[n++] = "HOME=" + getSystemProperty("user.home");
68 if(!envHas("SHELL",extra)) defaults[n++] = "SHELL=/bin/sh";
69 if(!envHas("TERM",extra)) defaults[n++] = "TERM=vt100";
70 if(!envHas("TZ",extra)) defaults[n++] = "TZ=" + posixTZ();
71 String[] env = new String[extra.length+n];
72 for(int i=0;i<n;i++) env[i] = defaults[i];
73 for(int i=0;i<extra.length;i++) env[n++] = extra[i];
77 protected void _start() {
78 if(addTask(this) < 0) throw new Error("Task list full");
81 protected void _exit() {
83 if(ppid == 0) removeTask(this);
84 for(int i=0;i<MAX_TASKS;i++) {
85 if(tasks[i] != null && tasks[i].ppid == pid) {
86 if(tasks[i].state == DONE) removeTask(tasks[i]);
87 else tasks[i].ppid = 0;
91 if(ppid != 0) synchronized(tasks[ppid].waitNotification) { tasks[ppid].waitNotification.notify(); }
95 protected int syscall(int syscall, int a, int b, int c, int d) {
97 case SYS_kill: return sys_kill(a,b);
98 case SYS_fork: return sys_fork();
99 case SYS_pipe: return sys_pipe(a);
100 case SYS_dup2: return sys_dup2(a,b);
101 case SYS_waitpid: return sys_waitpid(a,b,c);
102 default: return super.syscall(syscall,a,b,c,d);
106 /** The kill syscall.
107 SIGSTOP, SIGTSTO, SIGTTIN, and SIGTTOUT pause the process.
108 SIGCONT, SIGCHLD, SIGIO, and SIGWINCH are ignored.
109 Anything else terminates the process. */
110 private int sys_kill(int pid, int signal) {
111 // This will only be called by raise() in newlib to invoke the default handler
112 // We don't have to worry about actually delivering the signal
113 if(pid != pid) return -ESRCH;
114 if(signal < 0 || signal >= 32) return -EINVAL;
129 String msg = "Terminating on signal: " + signal + "\n";
133 System.out.print(msg);
136 byte[] b = msg.getBytes("US-ASCII");
137 fds[2].write(b,0,b.length);
139 catch(UnsupportedEncodingException e){ throw new Error(e.getMessage()); }
140 catch(IOException e) { }
147 private int sys_waitpid(int pid, int statusAddr, int options) {
148 final int WNOHANG = 1;
149 if((options & ~(WNOHANG)) != 0) return -EINVAL;
150 if(pid !=-1 && (pid <= 0 || pid >= MAX_TASKS)) return -ECHILD;
152 synchronized(tasks) {
153 UnixRuntime task = null;
155 for(int i=0;i<MAX_TASKS;i++) {
156 if(tasks[i] != null && tasks[i].ppid == this.pid && tasks[i].state == DONE) {
161 } else if(tasks[pid] != null && tasks[pid].ppid == this.pid && tasks[pid].state == DONE) {
168 if(statusAddr!=0) memWrite(statusAddr,task.exitStatus()<<8);
169 } catch(FaultException e) {
176 if((options&WNOHANG)!=0) return 0;
177 synchronized(waitNotification) {
178 try { waitNotification.wait(); } catch(InterruptedException e) { throw new Error(e); }
183 // Great ugliness lies within.....
184 private int sys_fork() {
185 CPUState state = getCPUState();
186 int sp = state.r[SP];
189 r = (UnixRuntime) getClass().newInstance();
190 } catch(Exception e) {
191 System.err.println(e);
194 int child_pid = addTask(r);
195 if(child_pid < 0) return -ENOMEM;
199 r.fds = new FD[OPEN_MAX];
200 for(int i=0;i<OPEN_MAX;i++) if(fds[i] != null) r.fds[i] = fds[i].dup();
202 for(int i=0;i<TOTAL_PAGES;i++) {
203 if(readPages[i] == null) continue;
204 if(isEmptyPage(writePages[i])) {
205 r.readPages[i] = r.writePages[i] = writePages[i];
206 } else if(writePages[i] != null) {
207 r.readPages[i] = r.writePages[i] = new int[PAGE_WORDS];
208 if(STACK_BOTTOM == 0 || i*PAGE_SIZE < STACK_BOTTOM || i*PAGE_SIZE >= sp-PAGE_SIZE*2)
209 System.arraycopy(writePages[i],0,r.writePages[i],0,PAGE_WORDS);
211 r.readPages[i] = r.readPages[i];
216 r.setCPUState(state);
223 } catch(Exception e) {
224 System.err.println("Forked process threw exception: ");
233 private int sys_pipe(int addr) {
234 PipedOutputStream writerStream = new PipedOutputStream();
235 PipedInputStream readerStream;
237 readerStream = new PipedInputStream(writerStream);
238 } catch(IOException e) {
241 FD reader = new InputStreamFD(readerStream);
242 FD writer = new OutputStreamFD(writerStream);
243 int fd1 = allocFDEnt(reader);
244 if(fd1 < 0) return -ENFILE;
245 int fd2 = allocFDEnt(writer);
246 if(fd2 < 0) { closeFDEnt(fd1); return -ENFILE; }
249 memWrite(addr+4,fd2);
250 } catch(FaultException e) {
258 private int sys_dup2(int oldd, int newd) {
259 if(oldd == newd) return 0;
263 if(oldFD == null) return -EBADFD;
264 } catch(ArrayIndexOutOfBoundsException e) {
268 if(fds[newd] != null) fds[newd].close();
269 fds[newd] = oldFD.dup();
270 } catch(ArrayIndexOutOfBoundsException e) {