/** Table containing all open file descriptors. (Entries are null if the fd is not in use */
FD[] fds; // package-private for UnixRuntime
boolean closeOnExec[];
+
+ /** Table of all current file locks held by this process. */
+ Seekable.Lock[] locks;
+ public static final int LOCK_MAX = 8;
/** Pointer to a SecurityManager for this process */
SecurityManager sm;
/** Subclasses should return the address of the symbol <i>symbol</i> or -1 it it doesn't exits in this method
This method is only required if the call() function is used */
- protected int lookupSymbol(String symbol) { return -1; }
+ public int lookupSymbol(String symbol) { return -1; }
/** Subclasses should populate a CPUState object representing the cpu state */
protected abstract void getCPUState(CPUState state);
r.startTime = 0;
r.fds = new FD[OPEN_MAX];
for(int i=0;i<OPEN_MAX;i++) if(fds[i] != null) r.fds[i] = fds[i].dup();
+ r.locks = new Seekable.Lock[LOCK_MAX];
int totalPages = writePages.length;
r.readPages = new int[totalPages][];
r.writePages = new int[totalPages][];
if(!exec) {
fds = new FD[OPEN_MAX];
closeOnExec = new boolean[OPEN_MAX];
+ locks = new Seekable.Lock[LOCK_MAX];
InputStream stdin = win32Hacks ? new Win32ConsoleIS(System.in) : System.in;
addFD(new TerminalFD(stdin));
public final void start(String[] args, String[] environ) {
int top, sp, argsAddr, envAddr;
if(state != STOPPED) throw new IllegalStateException("start() called in inappropriate state");
-
if(args == null) args = new String[]{getClass().getName()};
sp = top = writePages.length*(1<<pageShift);
if(state == EXITED || state == EXECED) throw new IllegalStateException("closeFD called in inappropriate state");
if(fdn < 0 || fdn >= OPEN_MAX) return false;
if(fds[fdn] == null) return false;
+
+ // release all fcntl locks on this file
+ Seekable s = fds[fdn].seekable();
+ if (s != null) {
+ try {
+ for (int i=0; i < LOCK_MAX; i++) {
+ if (locks[i] != null && s.equals(locks[i].seekable())) {
+ locks[i].release();
+ locks[i] = null;
+ }
+ }
+ } catch (IOException e) { throw new RuntimeException(e); }
+ }
+
fds[fdn].close();
fds[fdn] = null;
return true;
copyout(buf,addr,n);
return n;
}
+
+ /** The ftruncate syscall */
+ private int sys_ftruncate(int fdn, long length) {
+ if (fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if (fds[fdn] == null) return -EBADFD;
+
+ Seekable seekable = fds[fdn].seekable();
+ if (length < 0 || seekable == null) return -EINVAL;
+ try { seekable.resize(length); } catch (IOException e) { return -EIO; }
+ return 0;
+ }
/** The close syscall */
private int sys_close(int fdn) {
return 0;
}
- private int sys_fcntl(int fdn, int cmd, int arg) {
+ private int sys_fcntl(int fdn, int cmd, int arg) throws FaultException {
int i;
if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
return 0;
case F_GETFD:
return closeOnExec[fdn] ? 1 : 0;
+ case F_GETLK:
+ case F_SETLK:
+ try {
+ return sys_fcntl_lock(fd, cmd, arg);
+ } catch (IOException e) { throw new RuntimeException(e);}
default:
if(STDERR_DIAG) System.err.println("WARNING: Unknown fcntl command: " + cmd);
return -ENOSYS;
}
}
+
+ /** Implements the F_GETLK and F_SETLK cases of fcntl syscall.
+ * If l_start = 0 and l_len = 0 the lock refers to the entire file.
+ struct flock {
+ short l_type; // lock type: F_UNLCK, F_RDLCK, F_WRLCK
+ short l_whence; // type of l_start: SEEK_SET, SEEK_CUR, SEEK_END
+ long l_start; // starting offset, bytes
+ long l_len; // len = 0 means until EOF
+ short l_pid; // lock owner
+ short l_xxx; // padding
+ };
+ */
+ private int sys_fcntl_lock(FD fd, int cmd, int arg)
+ throws FaultException, IOException {
+ if (arg == 0) { System.out.println("BAD ARG"); return -EINVAL; }
+ int word = memRead(arg);
+ int l_start = memRead(arg+4);
+ int l_len = memRead(arg+8);
+ int l_type = word>>16;
+ int l_whence = word&0x00ff;
+
+ Seekable s = fd.seekable();
+ if (s == null) return -EINVAL;
+
+ switch (l_whence) {
+ case SEEK_SET: break;
+ case SEEK_CUR: l_start += s.pos(); break;
+ case SEEK_END: l_start += s.length(); break;
+ default: return -1;
+ }
+
+ if (cmd != F_GETLK && cmd != F_SETLK) return -EINVAL;
+
+ if (cmd == F_GETLK) {
+ // Check if an l_type lock can be aquired. The only way to
+ // do this within the Java API is to try and create a lock.
+ Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK);
+
+ if (lock != null) {
+ // no lock exists
+ memWrite(arg, SEEK_SET|(F_UNLCK<<16));
+ lock.release();
+ }
+
+ return 0;
+ }
+
+ // now processing F_SETLK
+ if (cmd != F_SETLK) return -EINVAL;
+
+ if (l_type == F_UNLCK) {
+ // release all locks that fall within the boundaries given
+ for (int i=0; i < LOCK_MAX; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+
+ int pos = (int)locks[i].position();
+ if (pos < l_start) continue;
+ if (l_start != 0 && l_len != 0) // start/len 0 means unlock all
+ if (pos + locks[i].size() > l_start + l_len)
+ continue;
+
+ locks[i].release();
+ locks[i] = null;
+ }
+ return 0;
+
+ } else if (l_type == F_RDLCK || l_type == F_WRLCK) {
+ // first see if a lock already exists
+ for (int i=0; i < LOCK_MAX; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+ int pos = (int)locks[i].position();
+ int size = (int)locks[i].size();
+ if (l_start < pos && pos + size < l_start + l_len) {
+ // found a lock contained in the new requested lock
+ locks[i].release();
+ locks[i] = null;
+
+ } else if (l_start >= pos && pos + size >= l_start + l_len) {
+ // found a lock that contains the requested lock
+ if (locks[i].isShared() == (l_type == F_RDLCK)) {
+ memWrite(arg+4, pos);
+ memWrite(arg+8, size);
+ return 0;
+ } else {
+ locks[i].release();
+ locks[i] = null;
+ }
+ }
+ }
+
+ // create the lock
+ Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK);
+ if (lock == null) return -EAGAIN;
+
+ int i;
+ for (i=0; i < LOCK_MAX; i++)
+ if (locks[i] == null) break;
+ if (i == LOCK_MAX) return -ENOLCK;
+ locks[i] = lock;
+ return 0;
+
+ } else {
+ return -EINVAL;
+ }
+ }
+
/** The syscall dispatcher.
The should be called by subclasses when the syscall instruction is invoked.
protected final int syscall(int syscall, int a, int b, int c, int d, int e, int f) {
try {
int n = _syscall(syscall,a,b,c,d,e,f);
- //if(n < 0) System.err.println("syscall: " + syscall + " returned " + n);
+ //if(n<0) throw new ErrnoException(-n);
return n;
} catch(ErrnoException ex) {
+ //System.err.println("While executing syscall: " + syscall + ":");
+ //if(syscall == SYS_open) try { System.err.println("Failed to open " + cstring(a) + " errno " + ex.errno); } catch(Exception e2) { }
//ex.printStackTrace();
return -ex.errno;
} catch(FaultException ex) {
case SYS_close: return sys_close(a);
case SYS_read: return sys_read(a,b,c);
case SYS_lseek: return sys_lseek(a,b,c);
+ case SYS_ftruncate: return sys_ftruncate(a,b);
case SYS_getpid: return sys_getpid();
case SYS_calljava: return sys_calljava(a,b,c,d);
case SYS_gettimeofday: return sys_gettimeofday(a,b);
}
return addr;
}
-
+
+ // TODO: less memory copying (custom utf-8 reader)
+ // or at least roll strlen() into copyin()
+ public final String utfstring(int addr) throws ReadFaultException {
+ if (addr == 0) return null;
+
+ // determine length
+ int i=addr;
+ for(int word = 1; word != 0; i++) {
+ word = memRead(i&~3);
+ switch(i&3) {
+ case 0: word = (word>>>24)&0xff; break;
+ case 1: word = (word>>>16)&0xff; break;
+ case 2: word = (word>>> 8)&0xff; break;
+ case 3: word = (word>>> 0)&0xff; break;
+ }
+ }
+ if (i > addr) i--; // do not count null
+
+ byte[] bytes = new byte[i-addr];
+ copyin(addr, bytes, bytes.length);
+
+ try {
+ return new String(bytes, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e); // should never happen with UTF-8
+ }
+ }
+
/** Helper function to read a cstring from main memory */
public final String cstring(int addr) throws ReadFaultException {
+ if (addr == 0) return null;
StringBuffer sb = new StringBuffer();
for(;;) {
int word = memRead(addr&~3);
pos++; len--; pb = true;
}
int n = parent.read(buf,pos,len);
- if(n == -1) return -1;
+ if(n == -1) return pb ? 1 : -1;
for(int i=0;i<n;i++) {
if(buf[pos+i] == '\r') {
if(i==n-1) {
static byte[] getBytes(String s) {
try {
- return s.getBytes("ISO-8859-1");
+ return s.getBytes("UTF-8");
} catch(UnsupportedEncodingException e) {
return null; // should never happen
}