#include "inc/priv.h"#include <tos.h>#include "inc/nan.h"#include "inc/process.h"#include "inc/time.h"#include "lsd.h" u64intsec_realtime(void){ return nsec();} void *sl_segalloc(usize sz){ return segattach(SG_CEXEC, "memory", nil, sz);} voidsl_segfree(void *s, usize sz){ USED(sz); if(s != nil) segdetach(s);} voidsl_segused(void *s, usize sz, usize used){ USED(s); USED(sz); USED(used);} /* * nsec() is wallclock and can be adjusted by timesync * so need to use cycles() instead, but fall back to * nsec() in case we can't */u64intnanosec_monotonic(void){ static u64int fasthz, xstart; u64int x; if(fasthz == ~0ULL) return nsec() - xstart; if(fasthz == 0){ if(_tos->cyclefreq){ fasthz = _tos->cyclefreq; cycles(&xstart); }else{ fasthz = ~0ULL; xstart = nsec(); } return 0; } cycles(&x); x -= xstart; u64int q = x / fasthz; u64int r = x % fasthz; return q*Nsec + r*Nsec/fasthz;} voidtimestr(u64int ns, char *buf, int sz){ Tm tm; snprint(buf, sz, "%τ", tmfmt(tmtime(&tm, ns/Nsec, tzload("local")), nil));} u64intparsetime(const char *s){ Tm tm; if(tmparse(&tm, "?WWW, ?MM ?DD hh:mm:ss ?Z YYYY", s, tzload("local"), nil) == nil) return -1; return tmnorm(&tm)*Nsec;} voidsleep_ms(int ms){ if(ms != 0) sleep(ms);} intftruncate(int f, soffset sz){ Dir d; nulldir(&d); d.length = sz; return dirfwstat(f, &d) > 0 ? 0 : -1;} intunsetenv(const char *name){ char ename[100]; if(*name == 0 || strchr(name, '/') != nil || strcmp(name, ".") == 0 || strcmp(name, "..") == 0 || strlen(name) >= sizeof(ename)-5){ werrstr("bad env name: %s", name); return -1; } snprint(ename, sizeof(ename), "/env/%s", name); if(access(ename, AEXIST) == 0) return remove(ename); return 0;} voidsys_setcurrpc(int dummy){ USED(dummy); sys_setcallpc(dummy);} voidsys_seed(void *p, int sz){ u8int *o = p; int f; if((f = open("/dev/random", OREAD)) >= 0){ while(sz > 0){ int n = read(f, o, sz); if(n < 0) break; o += n; sz -= n; } close(f); } // otherwise TOO BAD} intsys_read(int fd, u8int *buf, usize n, usize *nread){ ssize r; while(1){ r = read(fd, buf, n); if(r > -1){ *nread = (usize)r; break; } return r; } return 0;} intsys_write(int fd, const void *buf, usize n, usize *nwritten){ ssize r = write(fd, buf, n); if(r < 0) return -1; *nwritten = (usize)r; return 0;} intsys_open(const char *fname, ios_flags flags, usize mode){ int of = (flags & IOS_WRITE) ? ((flags & IOS_READ) ? ORDWR : OWRITE) : OREAD; if(flags & IOS_TRUNC) of |= OTRUNC; if(flags & IOS_EXCL) of |= OEXCL; of |= OCEXEC; if(flags & IOS_APPEND) mode |= DMAPPEND; return (flags & IOS_CREATE) ? create(fname, of, mode) : open(fname, of);} intsys_rename(const char *old, const char *new){ Dir d; nulldir(&d); d.name = (char*)new; return dirwstat(old, &d) > 0 ? 0 : -1;} soffsetsys_seek(int fd, soffset offset, int whence){ return seek(fd, offset, whence);} intsys_close(int fd){ return close(fd);} intsys_dup(int oldfd, int newfd){ return dup(oldfd, newfd);} voidsys_fd_setup(int fd){ USED(fd);} intsys_exec(const char *path, char *const argv[], char *env[]){ if(env != nil){ for(int i = 0; env[i] != nil; i++){ char *v = strchr(env[i], '='); if(v == nil) abort(); *v++ = 0; if(putenv(env[i], v) != 0) return -1; } } return exec(path, argv);} intsys_fork(fork_flags flags){ int rf = RFFDG|RFREND|RFPROC; if(flags & FORK_CLEAR_ENV) rf |= RFCENVG; return rfork(rf);} char *sys_getcwd(void){ char tmp[4096]; if(getwd(tmp, sizeof(tmp)) != nil) return MEM_STRDUP(tmp); return nil;} intsys_chdir(int fd, const char *dir){ USED(fd); return chdir(dir);} intsys_pipe(int fd[2], bool rd, bool wr){ if(pipe(fd) != 0) return -1; if(!rd) write(fd[1], "", 0); if(!wr) write(fd[0], "", 0); return 0;} char *sys_find_program(const char *p){ if((p[0] == '/') || (p[0] == '.' && p[1] == '/') || (p[0] == '.' && p[1] == '.' && p[2] == '/')) return MEM_STRDUP(p); char *path = getenv("path"); if(path == nil) return nil; char *s; for(s = path; s != nil;){ char *e = strchr(s, ' '); if(e != nil) *e = 0; s = smprint("%s/%s", s, p); if(s != nil){ int r = access(s, AEXEC); if(r == 0) break; free(s); } s = e != nil ? e+1 : nil; } free(path); return s;} static intmkdir_(const char *path, usize mode){ Dir *d; int r = -1; if((d = dirstat(path)) != nil){ if((d->mode & DMDIR) != 0) r = 0; free(d); }else{ int f = create(path, OREAD, DMDIR|mode); if(f >= 0) r = 0; close(f); } return r;} intsys_mkdir(const char *path, usize mode){ if(mkdir_(path, mode) == 0) return 0; char *p = MEM_STRDUP(path); if(p == nil) return -1; int r = -1; for(char *s = p+1; (s = strchr(s, '/')) != nil;){ *s = 0; if(mkdir_(p, mode) != 0) goto done; *s++ = '/'; while(*s == '/') s++; } if(mkdir_(path, mode) == 0) r = 0;done: MEM_FREE(p); return r;} intsys_postnote(int pid, const char *note, const char *sig){ USED(sig); return postnote(PNPROC, pid, note);} BUILTIN("getpid", getpid){ USED(args); noargs(); return fixnum(getpid());} static voidprocess_updates(int f){ char wait[128]; snprint(wait, sizeof(wait), "/proc/%lud/args", (ulong)getpid()); int nfd = open(wait, OWRITE|OCEXEC); if(nfd >= 0){ fprint(nfd, "process_updates"); close(nfd); } for(;;){ char *waitfld[5]; int n = read(f, wait, sizeof(wait)-1); if(n <= 0) break; wait[n] = 0; if(tokenize(wait, waitfld, nelem(waitfld)) != nelem(waitfld)) continue; int pid = atoi(waitfld[0]); char *m = waitfld[4]; // the only way the status isn't there is if the process has // already left the building char stat[128], *statfld[5]; process_state_t state = PSTATE_EXITED; snprint(stat, sizeof(stat), "/proc/%s/status", waitfld[0]); int s = open(stat, OREAD|OCEXEC); if(s >= 0){ n = read(s, stat, sizeof(stat)-1); close(s); if(n > 0){ stat[n] = 0; if(tokenize(stat, statfld, nelem(statfld)) >= nelem(statfld)){ if(strcmp(statfld[2], "Broken") == 0) state = PSTATE_DUMPED; else if(strcmp(statfld[2], "Stopped") == 0) state = PSTATE_STOPPED; else if(strcmp(statfld[2], "Moribund") == 0) state = PSTATE_EXITED; else state = PSTATE_RUNNING; } } } process_update(pid, state, *m == 0 ? 0 : 1, *m == 0 ? nil : m); } exits(nil);} voidsys_init(void){ lsd_init(); char t[64]; snprint(t, sizeof(t), "/proc/%d/wait", getpid()); int waitfd = open(t, OREAD|OCEXEC); if(waitfd < 0) abort(); int r = rfork(RFREND|RFPROC|RFMEM); if(r < 0) abort(); if(r == 0) process_updates(waitfd);} extern uchar bootcode[];extern ulong bootlen; voidmain(int argc, char **argv){ argv0 = argv[0]; setfcr(FPPDBL|FPRNR|FPOVFL); tmfmtinstall(); slmain(bootcode, bootlen, argc, argv);}
#include "inc/priv.h"
#include <tos.h>
#include "inc/nan.h"
#include "inc/process.h"
#include "inc/time.h"
#include "lsd.h"
u64int
sec_realtime(void)
{
return nsec();
}
void *
sl_segalloc(usize sz)
{
return segattach(SG_CEXEC, "memory", nil, sz);
}
void
sl_segfree(void *s, usize sz)
{
USED(sz);
if(s != nil)
segdetach(s);
}
void
sl_segused(void *s, usize sz, usize used)
{
USED(s); USED(sz); USED(used);
}
/*
* nsec() is wallclock and can be adjusted by timesync
* so need to use cycles() instead, but fall back to
* nsec() in case we can't
*/
u64int
nanosec_monotonic(void)
{
static u64int fasthz, xstart;
u64int x;
if(fasthz == ~0ULL)
return nsec() - xstart;
if(fasthz == 0){
if(_tos->cyclefreq){
fasthz = _tos->cyclefreq;
cycles(&xstart);
}else{
fasthz = ~0ULL;
xstart = nsec();
}
return 0;
}
cycles(&x);
x -= xstart;
u64int q = x / fasthz;
u64int r = x % fasthz;
return q*Nsec + r*Nsec/fasthz;
}
void
timestr(u64int ns, char *buf, int sz)
{
Tm tm;
snprint(buf, sz, "%τ", tmfmt(tmtime(&tm, ns/Nsec, tzload("local")), nil));
}
u64int
parsetime(const char *s)
{
Tm tm;
if(tmparse(&tm, "?WWW, ?MM ?DD hh:mm:ss ?Z YYYY", s, tzload("local"), nil) == nil)
return -1;
return tmnorm(&tm)*Nsec;
}
void
sleep_ms(int ms)
{
if(ms != 0)
sleep(ms);
}
int
ftruncate(int f, soffset sz)
{
Dir d;
nulldir(&d);
d.length = sz;
return dirfwstat(f, &d) > 0 ? 0 : -1;
}
int
unsetenv(const char *name)
{
char ename[100];
if(*name == 0 || strchr(name, '/') != nil ||
strcmp(name, ".") == 0 || strcmp(name, "..") == 0 ||
strlen(name) >= sizeof(ename)-5){
werrstr("bad env name: %s", name);
return -1;
}
snprint(ename, sizeof(ename), "/env/%s", name);
if(access(ename, AEXIST) == 0)
return remove(ename);
return 0;
}
void
sys_setcurrpc(int dummy)
{
USED(dummy);
sys_setcallpc(dummy);
}
void
sys_seed(void *p, int sz)
{
u8int *o = p;
int f;
if((f = open("/dev/random", OREAD)) >= 0){
while(sz > 0){
int n = read(f, o, sz);
if(n < 0)
break;
o += n;
sz -= n;
}
close(f);
}
// otherwise TOO BAD
}
int
sys_read(int fd, u8int *buf, usize n, usize *nread)
{
ssize r;
while(1){
r = read(fd, buf, n);
if(r > -1){
*nread = (usize)r;
break;
}
return r;
}
return 0;
}
int
sys_write(int fd, const void *buf, usize n, usize *nwritten)
{
ssize r = write(fd, buf, n);
if(r < 0)
return -1;
*nwritten = (usize)r;
return 0;
}
int
sys_open(const char *fname, ios_flags flags, usize mode)
{
int of =
(flags & IOS_WRITE)
? ((flags & IOS_READ) ? ORDWR : OWRITE)
: OREAD;
if(flags & IOS_TRUNC)
of |= OTRUNC;
if(flags & IOS_EXCL)
of |= OEXCL;
of |= OCEXEC;
if(flags & IOS_APPEND)
mode |= DMAPPEND;
return
(flags & IOS_CREATE)
? create(fname, of, mode)
: open(fname, of);
}
int
sys_rename(const char *old, const char *new)
{
Dir d;
nulldir(&d);
d.name = (char*)new;
return dirwstat(old, &d) > 0 ? 0 : -1;
}
soffset
sys_seek(int fd, soffset offset, int whence)
{
return seek(fd, offset, whence);
}
int
sys_close(int fd)
{
return close(fd);
}
int
sys_dup(int oldfd, int newfd)
{
return dup(oldfd, newfd);
}
void
sys_fd_setup(int fd)
{
USED(fd);
}
int
sys_exec(const char *path, char *const argv[], char *env[])
{
if(env != nil){
for(int i = 0; env[i] != nil; i++){
char *v = strchr(env[i], '=');
if(v == nil)
abort();
*v++ = 0;
if(putenv(env[i], v) != 0)
return -1;
}
}
return exec(path, argv);
}
int
sys_fork(fork_flags flags)
{
int rf = RFFDG|RFREND|RFPROC;
if(flags & FORK_CLEAR_ENV)
rf |= RFCENVG;
return rfork(rf);
}
char *
sys_getcwd(void)
{
char tmp[4096];
if(getwd(tmp, sizeof(tmp)) != nil)
return MEM_STRDUP(tmp);
return nil;
}
int
sys_chdir(int fd, const char *dir)
{
USED(fd);
return chdir(dir);
}
int
sys_pipe(int fd[2], bool rd, bool wr)
{
if(pipe(fd) != 0)
return -1;
if(!rd)
write(fd[1], "", 0);
if(!wr)
write(fd[0], "", 0);
return 0;
}
char *
sys_find_program(const char *p)
{
if((p[0] == '/') ||
(p[0] == '.' && p[1] == '/') ||
(p[0] == '.' && p[1] == '.' && p[2] == '/'))
return MEM_STRDUP(p);
char *path = getenv("path");
if(path == nil)
return nil;
char *s;
for(s = path; s != nil;){
char *e = strchr(s, ' ');
if(e != nil)
*e = 0;
s = smprint("%s/%s", s, p);
if(s != nil){
int r = access(s, AEXEC);
if(r == 0)
break;
free(s);
}
s = e != nil ? e+1 : nil;
}
free(path);
return s;
}
static int
mkdir_(const char *path, usize mode)
{
Dir *d;
int r = -1;
if((d = dirstat(path)) != nil){
if((d->mode & DMDIR) != 0)
r = 0;
free(d);
}else{
int f = create(path, OREAD, DMDIR|mode);
if(f >= 0)
r = 0;
close(f);
}
return r;
}
int
sys_mkdir(const char *path, usize mode)
{
if(mkdir_(path, mode) == 0)
return 0;
char *p = MEM_STRDUP(path);
if(p == nil)
return -1;
int r = -1;
for(char *s = p+1; (s = strchr(s, '/')) != nil;){
*s = 0;
if(mkdir_(p, mode) != 0)
goto done;
*s++ = '/';
while(*s == '/')
s++;
}
if(mkdir_(path, mode) == 0)
r = 0;
done:
MEM_FREE(p);
return r;
}
int
sys_postnote(int pid, const char *note, const char *sig)
{
USED(sig);
return postnote(PNPROC, pid, note);
}
BUILTIN("getpid", getpid)
{
USED(args);
noargs();
return fixnum(getpid());
}
static void
process_updates(int f)
{
char wait[128];
snprint(wait, sizeof(wait), "/proc/%lud/args", (ulong)getpid());
int nfd = open(wait, OWRITE|OCEXEC);
if(nfd >= 0){
fprint(nfd, "process_updates");
close(nfd);
}
for(;;){
char *waitfld[5];
int n = read(f, wait, sizeof(wait)-1);
if(n <= 0)
break;
wait[n] = 0;
if(tokenize(wait, waitfld, nelem(waitfld)) != nelem(waitfld))
continue;
int pid = atoi(waitfld[0]);
char *m = waitfld[4];
// the only way the status isn't there is if the process has
// already left the building
char stat[128], *statfld[5];
process_state_t state = PSTATE_EXITED;
snprint(stat, sizeof(stat), "/proc/%s/status", waitfld[0]);
int s = open(stat, OREAD|OCEXEC);
if(s >= 0){
n = read(s, stat, sizeof(stat)-1);
close(s);
if(n > 0){
stat[n] = 0;
if(tokenize(stat, statfld, nelem(statfld)) >= nelem(statfld)){
if(strcmp(statfld[2], "Broken") == 0)
state = PSTATE_DUMPED;
else if(strcmp(statfld[2], "Stopped") == 0)
state = PSTATE_STOPPED;
else if(strcmp(statfld[2], "Moribund") == 0)
state = PSTATE_EXITED;
else
state = PSTATE_RUNNING;
}
}
}
process_update(pid, state, *m == 0 ? 0 : 1, *m == 0 ? nil : m);
}
exits(nil);
}
void
sys_init(void)
{
lsd_init();
char t[64];
snprint(t, sizeof(t), "/proc/%d/wait", getpid());
int waitfd = open(t, OREAD|OCEXEC);
if(waitfd < 0)
abort();
int r = rfork(RFREND|RFPROC|RFMEM);
if(r < 0)
abort();
if(r == 0)
process_updates(waitfd);
}
extern uchar bootcode[];
extern ulong bootlen;
void
main(int argc, char **argv)
{
argv0 = argv[0];
setfcr(FPPDBL|FPRNR|FPOVFL);
tmfmtinstall();
slmain(bootcode, bootlen, argc, argv);
}