#include "inc/priv.h"#include "inc/cvalues.h"#include "inc/print.h"#include "inc/io.h"#include "inc/process.h"#include "inc/types.h" static const sl_type *processtype;static sl_v runningsym, exitedsym, stoppedsym, signaledsym;static sl_v iosym, insym, outsym, errsym, envsym, dirsym;static const int iosflags[] = { IOS_READ, IOS_CREATE|IOS_WRITE|IOS_TRUNC, IOS_CREATE|IOS_WRITE|IOS_TRUNC};static int nullfd[3]; typedef struct sl_process sl_process; struct sl_pid { int pid; int code; bool dumped; sl_v state; char *msg; sl_pid *next; // FIXME(sigrid): binary tree}; struct sl_process { sl_pid *pid; sl_v stream[3];}; static boolisprocess(sl_v v){ return iscvalue(v) && cvalue_class(v) == processtype;} static sl_process *toprocess(sl_v v){ if(sl_likely(isprocess(v))) return cvalue_data(v); cthrow(type_error("value", "process", v), v);} BUILTIN("find-program", find_program){ argcount(1); char *path = sys_find_program(tostr(args[0])); if(path == nil) return sl_nil; sl_v v = str_from_cstr(path); MEM_FREE(path); return v;} BUILTIN("process?", processp){ argcount(1); return isprocess(args[0]);} BUILTIN("process-alive?", process_alivep){ argcount(1); sl_pid *pid = toprocess(args[0])->pid; return pid->state != runningsym && pid->state != stoppedsym ? sl_nil : sl_t;} BUILTIN("process-core-dumped?", process_code_dumpedp){ argcount(1); sl_pid *pid = toprocess(args[0])->pid; return pid->dumped ? sl_t : sl_nil;} BUILTIN("process-state", process_state){ argcount(1); return toprocess(args[0])->pid->state;} BUILTIN("process-exit-code", process_exit_code){ argcount(1); sl_process *proc = toprocess(args[0]); if(proc->pid->code < 0) return sl_nil; return fixnum(proc->pid->code);} BUILTIN("process-exit-msg", process_exit_msg){ argcount(1); sl_process *proc = toprocess(args[0]); if(proc->pid == nil || proc->pid->code < 0) return sl_nil; if(proc->pid->code == 0 || proc->pid->msg == nil) return sl_emptystr; return str_from_cstr(proc->pid->msg);} static sl_vprocess_stream(sl_v p, int n){ sl_process *proc = toprocess(p); return proc->stream[n];} BUILTIN("process-input", process_input){ argcount(1); return process_stream(args[0], 0);} BUILTIN("process-output", process_output){ argcount(1); return process_stream(args[0], 1);} BUILTIN("process-error", process_error){ argcount(1); return process_stream(args[0], 2);} BUILTIN("make-process", make_process){ const char *const fds[] = {"in", "out", "err"}; sl_v keys[] = {insym, outsym, errsym, envsym, dirsym}; sl_v values[nelem(keys)]; nargs = sl_process_args(args, 2, nargs, keys, nelem(keys), values); argcount(2); int argc = 0, fd[3]; int closefd[3], numclosefd = 0; int chclosefd[3], numchclosefd = 0; sl_v stream[3] = {sl_nil, sl_nil, sl_nil}; char *program = MEM_STRDUP(tostr(args[0])), **argv = nil, **env = nil; sl_pid *pid = nil; int dirfd = -1; for(int i = 0; i < nelem(values); i++) sl_gc_handle(&values[i]); sl_gc_handle(&stream[0]); sl_gc_handle(&stream[1]); sl_gc_handle(&stream[2]); sl_v v = sl_nil, err = sl_nil; SL_TRY{ // collect argv sl_v a = args[1]; (void)tocons(a); argc = llength(args[1]); if((argv = MEM_ALLOC((argc+1)*sizeof(char*))) == nil) bthrow(error(sl_errmem, "no memory for argv")); for(int i = 0; i < argc; i++, a = cdr_(a)){ argv[i] = nil; if(!iscons(a)) bthrow(type_error("argv", "cons", a)); sl_v s = car_(a); if(!isstr(s)) bthrow(type_error("arg", "str", s)); if((argv[i] = MEM_STRDUP(tostr(s))) == nil) bthrow(error(sl_errmem, "no memory for argv[%d]", i)); } argv[argc] = nil; // collect env sl_v e = values[3]; if(e != sl_unbound){ int ne = llength(e); if(e != sl_nil) (void)tocons(e); if((env = MEM_ALLOC((ne+1)*sizeof(char*))) == nil) bthrow(error(sl_errmem, "no memory for env")); for(int i = 0; i < ne; i++, e = cdr_(e)){ env[i] = nil; if(!iscons(e)) bthrow(type_error("env", "cons", e)); sl_v pair = car_(e); if(!iscons(pair)) bthrow(type_error("env", "assoc list", e)); const char *ek = tostr(car_(pair)), *ev = tostr(cdr_(pair)); int nk = strlen(ek), nv = strlen(ev), sz = nk+1+nv+1; if((env[i] = MEM_ALLOC(nk+1+nv+1)) == nil) bthrow(error(sl_errmem, "no memory for env[%d]", i)); snprintf(env[i], sz, "%s=%s", ek, ev); } env[ne] = nil; } // get the streams ready for(int i = 0; i < nelem(fd); i++){ sl_v io = values[i]; if(io == sl_t) fd[i] = i; else if(io == sl_unbound || io == sl_nil) fd[i] = nullfd[i]; else if(io == outsym && i == 2) fd[i] = fd[1]; else if(io == iosym){ stream[i] = cvalue(sl_iotype, sizeof(ios)); ios *s = value2c(ios*, stream[i]); ios_pipe(s, iosflags[i] & IOS_RDWR, &fd[i]); if(fd[i] < 0) bthrow(error(sl_errio, "%s: pipe failed", fds[i])); closefd[numclosefd++] = fd[i]; chclosefd[numchclosefd++] = s->fd; }else if(isio(io)){ ios *s = toio( io, true, (iosflags[i] & IOS_READ) != 0, (iosflags[i] & IOS_WRITE) != 0 ); if(s->fd < 0) bthrow(error(sl_errio, "%s: memory buffers not supported yet", fds[i])); // FIXME(sigrid) fd[i] = s->fd; }else if(isstr(io)){ fd[i] = sys_open(tostr(io), iosflags[i], 0644); if(fd[i] < 0) bthrow(error(sl_errio, "%s: could not open %s", fds[i], tostr(v))); closefd[numclosefd++] = fd[i]; }else bthrow(error(sl_errarg, "%s: invalid stream", fds[i])); } // init the pid if((pid = MEM_ALLOC(sizeof(sl_pid))) == nil) bthrow(error(sl_errmem, "no memory for pid")); pid->pid = -1; pid->code = -1; pid->msg = nil; pid->state = runningsym; pid->dumped = false; pid->next = slvm.pids; slvm.pids = pid; const sl_v dir = values[4]; // :dir const char *dirpath = nil; if(dir != sl_unbound && dir != sl_nil){ dirpath = tostr(dir); dirfd = sys_open(dirpath, IOS_DIR, 0); if(dirfd < 0) bthrow(error(sl_errarg, "dir: bad directory: %s", dirpath)); } // fork, close/deallocate parent's resources int chpid = sys_fork(env == nil ? 0 : FORK_CLEAR_ENV); if(chpid < 0) bthrow(error(sl_err, "fork failed")); if(chpid > 0){ // parent pid->pid = chpid; v = cvalue(processtype, sizeof(sl_process)); sl_process *process = value2c(sl_process*, v); process->pid = pid; for(int i = 0; i < nelem(fd); i++) process->stream[i] = stream[i]; }else{ // child for(int i = 0; i < numchclosefd; i++) sys_close(chclosefd[i]); if(dirfd >= 0){ if(sys_chdir(dirfd, dirpath) != 0) goto child_failed; sys_close(dirfd); } for(int i = 0; i < nelem(fd); i++){ if(sys_dup(fd[i], i) < 0) goto child_failed; } sys_exec(program, argv, env);child_failed:#if defined(__plan9__) sysfatal("make-process: %r");#else // FIXME(sigrid): check errno? pass it on to the parent? sysfatal("make-process failed");#endif } } SL_CATCH{ for(int i = 0; i < nelem(stream); i++){ if(isio(stream[i])) ios_close(value2c(ios*, stream[i])); } MEM_FREE(pid); err = sl.lasterror; } if(dirfd >= 0) sys_close(dirfd); for(int i = 0; i < numclosefd; i++) sys_close(closefd[i]); sl_free_gc_handles(nelem(values)+3); MEM_FREE(program); for(int i = 0; i < argc; i++) MEM_FREE(argv[i]); MEM_FREE(argv); if(env != nil){ for(int i = 0; env[i] != nil; i++) MEM_FREE(env[i]); MEM_FREE(env); } if(err != sl_nil) sl_raise(err); return v;} static voidprint_process(sl_v v){ sl_process *proc = toprocess(v); sl_print_str("#<process ", true); sl_print(fixnum(proc->pid->pid)); sl_v state = proc->pid->state; if(state != sl_nil){ sl_print_chr(' '); sl_print(state); if(state != runningsym && state != stoppedsym && proc->pid->code != 0){ sl_print_chr(' '); sl_print(fixnum(proc->pid->code)); if(proc->pid->msg != nil){ sl_print_str(" \"", true); sl_print_str(proc->pid->msg, false); sl_print_chr('"'); if(proc->pid->dumped) sl_print_str(" dumped", true); } } } sl_print_chr('>');} static voidrelocate_process(sl_v oldv, sl_v newv){ sl_process *p = toprocess(newv); for(int i = 0; i < nelem(p->stream); i++) p->stream[i] = sl_relocate(p->stream[i]); USED(oldv);} static voidfree_process(sl_v self){ sl_process *proc = value2c(sl_process*, self); sl_pid *p, *prev = nil; for(p = slvm.pids; p != nil; prev = p, p = p->next){ if(p == proc->pid){ if(prev == nil) slvm.pids = p->next; else prev->next = p->next; break; } } if(p == nil) abort(); MEM_FREE(p->msg); MEM_FREE(p); proc->pid = nil;} BUILTIN("process-close", process_close){ argcount(1); sl_process *proc = toprocess(args[0]); for(int i = 0; i < nelem(proc->stream); i++){ if(isio(proc->stream[i])) ios_close(value2c(ios*, proc->stream[i])); } return sl_void;} BUILTIN("process-post", process_post){ argcount(3); sl_process *proc = toprocess(args[0]); const char *note = tostr(args[1]); const char *sig = tosym(args[2])->name; return sys_postnote(proc->pid->pid, note, sig) == 0 ? sl_t : sl_nil;} static sl_cvtable process_vtable = { print_process, relocate_process, free_process, nil, nil,}; voidprocess_update(int pid, process_state_t state, int code, const char *msg){ for(sl_pid *p = slvm.pids; p != nil; p = p->next){ if(p->pid >= 0 && p->pid != pid) continue; switch(state){ case PSTATE_EXITED: p->state = exitedsym; break; case PSTATE_STOPPED: p->state = stoppedsym; break; case PSTATE_DUMPED: p->dumped = true; sl_fallthrough; case PSTATE_SIGNALED: p->state = signaledsym; break; case PSTATE_RUNNING: p->state = runningsym; break; } p->code = code; p->msg = msg == nil ? nil : MEM_STRDUP(msg); slvm.pidupdates++; // FIXME(sigrid): atomic break; } // GC'ed - nobody cares anymore} voidprocess_init(void){ if((nullfd[0] = sys_open(SYS_DEV_NULL, IOS_READ, 0)) < 0) sysfatal("%s", SYS_DEV_NULL); if((nullfd[1] = nullfd[2] = sys_open(SYS_DEV_NULL, IOS_WRITE, 0)) < 0) sysfatal("%s", SYS_DEV_NULL); processtype = define_opaque_type( mk_sym("process", false), sizeof(sl_process), &process_vtable, nil ); runningsym = mk_csym(":running"); exitedsym = mk_csym(":exited"); stoppedsym = mk_csym(":stopped"); signaledsym = mk_csym(":signaled"); insym = mk_csym(":in"); outsym = mk_csym(":out"); errsym = mk_csym(":err"); envsym = mk_csym(":env"); iosym = mk_csym(":io"); dirsym = mk_csym(":dir");}
#include "inc/priv.h"
#include "inc/cvalues.h"
#include "inc/print.h"
#include "inc/io.h"
#include "inc/process.h"
#include "inc/types.h"
static const sl_type *processtype;
static sl_v runningsym, exitedsym, stoppedsym, signaledsym;
static sl_v iosym, insym, outsym, errsym, envsym, dirsym;
static const int iosflags[] = {
IOS_READ,
IOS_CREATE|IOS_WRITE|IOS_TRUNC,
IOS_CREATE|IOS_WRITE|IOS_TRUNC
};
static int nullfd[3];
typedef struct sl_process sl_process;
struct sl_pid {
int pid;
int code;
bool dumped;
sl_v state;
char *msg;
sl_pid *next; // FIXME(sigrid): binary tree
};
struct sl_process {
sl_pid *pid;
sl_v stream[3];
};
static bool
isprocess(sl_v v)
{
return iscvalue(v) && cvalue_class(v) == processtype;
}
static sl_process *
toprocess(sl_v v)
{
if(sl_likely(isprocess(v)))
return cvalue_data(v);
cthrow(type_error("value", "process", v), v);
}
BUILTIN("find-program", find_program)
{
argcount(1);
char *path = sys_find_program(tostr(args[0]));
if(path == nil)
return sl_nil;
sl_v v = str_from_cstr(path);
MEM_FREE(path);
return v;
}
BUILTIN("process?", processp)
{
argcount(1);
return isprocess(args[0]);
}
BUILTIN("process-alive?", process_alivep)
{
argcount(1);
sl_pid *pid = toprocess(args[0])->pid;
return pid->state != runningsym && pid->state != stoppedsym ? sl_nil : sl_t;
}
BUILTIN("process-core-dumped?", process_code_dumpedp)
{
argcount(1);
sl_pid *pid = toprocess(args[0])->pid;
return pid->dumped ? sl_t : sl_nil;
}
BUILTIN("process-state", process_state)
{
argcount(1);
return toprocess(args[0])->pid->state;
}
BUILTIN("process-exit-code", process_exit_code)
{
argcount(1);
sl_process *proc = toprocess(args[0]);
if(proc->pid->code < 0)
return sl_nil;
return fixnum(proc->pid->code);
}
BUILTIN("process-exit-msg", process_exit_msg)
{
argcount(1);
sl_process *proc = toprocess(args[0]);
if(proc->pid == nil || proc->pid->code < 0)
return sl_nil;
if(proc->pid->code == 0 || proc->pid->msg == nil)
return sl_emptystr;
return str_from_cstr(proc->pid->msg);
}
static sl_v
process_stream(sl_v p, int n)
{
sl_process *proc = toprocess(p);
return proc->stream[n];
}
BUILTIN("process-input", process_input)
{
argcount(1);
return process_stream(args[0], 0);
}
BUILTIN("process-output", process_output)
{
argcount(1);
return process_stream(args[0], 1);
}
BUILTIN("process-error", process_error)
{
argcount(1);
return process_stream(args[0], 2);
}
BUILTIN("make-process", make_process)
{
const char *const fds[] = {"in", "out", "err"};
sl_v keys[] = {insym, outsym, errsym, envsym, dirsym};
sl_v values[nelem(keys)];
nargs = sl_process_args(args, 2, nargs, keys, nelem(keys), values);
argcount(2);
int argc = 0, fd[3];
int closefd[3], numclosefd = 0;
int chclosefd[3], numchclosefd = 0;
sl_v stream[3] = {sl_nil, sl_nil, sl_nil};
char *program = MEM_STRDUP(tostr(args[0])), **argv = nil, **env = nil;
sl_pid *pid = nil;
int dirfd = -1;
for(int i = 0; i < nelem(values); i++)
sl_gc_handle(&values[i]);
sl_gc_handle(&stream[0]);
sl_gc_handle(&stream[1]);
sl_gc_handle(&stream[2]);
sl_v v = sl_nil, err = sl_nil;
SL_TRY{
// collect argv
sl_v a = args[1];
(void)tocons(a);
argc = llength(args[1]);
if((argv = MEM_ALLOC((argc+1)*sizeof(char*))) == nil)
bthrow(error(sl_errmem, "no memory for argv"));
for(int i = 0; i < argc; i++, a = cdr_(a)){
argv[i] = nil;
if(!iscons(a))
bthrow(type_error("argv", "cons", a));
sl_v s = car_(a);
if(!isstr(s))
bthrow(type_error("arg", "str", s));
if((argv[i] = MEM_STRDUP(tostr(s))) == nil)
bthrow(error(sl_errmem, "no memory for argv[%d]", i));
}
argv[argc] = nil;
// collect env
sl_v e = values[3];
if(e != sl_unbound){
int ne = llength(e);
if(e != sl_nil)
(void)tocons(e);
if((env = MEM_ALLOC((ne+1)*sizeof(char*))) == nil)
bthrow(error(sl_errmem, "no memory for env"));
for(int i = 0; i < ne; i++, e = cdr_(e)){
env[i] = nil;
if(!iscons(e))
bthrow(type_error("env", "cons", e));
sl_v pair = car_(e);
if(!iscons(pair))
bthrow(type_error("env", "assoc list", e));
const char *ek = tostr(car_(pair)), *ev = tostr(cdr_(pair));
int nk = strlen(ek), nv = strlen(ev), sz = nk+1+nv+1;
if((env[i] = MEM_ALLOC(nk+1+nv+1)) == nil)
bthrow(error(sl_errmem, "no memory for env[%d]", i));
snprintf(env[i], sz, "%s=%s", ek, ev);
}
env[ne] = nil;
}
// get the streams ready
for(int i = 0; i < nelem(fd); i++){
sl_v io = values[i];
if(io == sl_t)
fd[i] = i;
else if(io == sl_unbound || io == sl_nil)
fd[i] = nullfd[i];
else if(io == outsym && i == 2)
fd[i] = fd[1];
else if(io == iosym){
stream[i] = cvalue(sl_iotype, sizeof(ios));
ios *s = value2c(ios*, stream[i]);
ios_pipe(s, iosflags[i] & IOS_RDWR, &fd[i]);
if(fd[i] < 0)
bthrow(error(sl_errio, "%s: pipe failed", fds[i]));
closefd[numclosefd++] = fd[i];
chclosefd[numchclosefd++] = s->fd;
}else if(isio(io)){
ios *s = toio(
io,
true,
(iosflags[i] & IOS_READ) != 0,
(iosflags[i] & IOS_WRITE) != 0
);
if(s->fd < 0)
bthrow(error(sl_errio, "%s: memory buffers not supported yet", fds[i])); // FIXME(sigrid)
fd[i] = s->fd;
}else if(isstr(io)){
fd[i] = sys_open(tostr(io), iosflags[i], 0644);
if(fd[i] < 0)
bthrow(error(sl_errio, "%s: could not open %s", fds[i], tostr(v)));
closefd[numclosefd++] = fd[i];
}else
bthrow(error(sl_errarg, "%s: invalid stream", fds[i]));
}
// init the pid
if((pid = MEM_ALLOC(sizeof(sl_pid))) == nil)
bthrow(error(sl_errmem, "no memory for pid"));
pid->pid = -1;
pid->code = -1;
pid->msg = nil;
pid->state = runningsym;
pid->dumped = false;
pid->next = slvm.pids;
slvm.pids = pid;
const sl_v dir = values[4]; // :dir
const char *dirpath = nil;
if(dir != sl_unbound && dir != sl_nil){
dirpath = tostr(dir);
dirfd = sys_open(dirpath, IOS_DIR, 0);
if(dirfd < 0)
bthrow(error(sl_errarg, "dir: bad directory: %s", dirpath));
}
// fork, close/deallocate parent's resources
int chpid = sys_fork(env == nil ? 0 : FORK_CLEAR_ENV);
if(chpid < 0)
bthrow(error(sl_err, "fork failed"));
if(chpid > 0){ // parent
pid->pid = chpid;
v = cvalue(processtype, sizeof(sl_process));
sl_process *process = value2c(sl_process*, v);
process->pid = pid;
for(int i = 0; i < nelem(fd); i++)
process->stream[i] = stream[i];
}else{ // child
for(int i = 0; i < numchclosefd; i++)
sys_close(chclosefd[i]);
if(dirfd >= 0){
if(sys_chdir(dirfd, dirpath) != 0)
goto child_failed;
sys_close(dirfd);
}
for(int i = 0; i < nelem(fd); i++){
if(sys_dup(fd[i], i) < 0)
goto child_failed;
}
sys_exec(program, argv, env);
child_failed:
#if defined(__plan9__)
sysfatal("make-process: %r");
#else
// FIXME(sigrid): check errno? pass it on to the parent?
sysfatal("make-process failed");
#endif
}
}
SL_CATCH{
for(int i = 0; i < nelem(stream); i++){
if(isio(stream[i]))
ios_close(value2c(ios*, stream[i]));
}
MEM_FREE(pid);
err = sl.lasterror;
}
if(dirfd >= 0)
sys_close(dirfd);
for(int i = 0; i < numclosefd; i++)
sys_close(closefd[i]);
sl_free_gc_handles(nelem(values)+3);
MEM_FREE(program);
for(int i = 0; i < argc; i++)
MEM_FREE(argv[i]);
MEM_FREE(argv);
if(env != nil){
for(int i = 0; env[i] != nil; i++)
MEM_FREE(env[i]);
MEM_FREE(env);
}
if(err != sl_nil)
sl_raise(err);
return v;
}
static void
print_process(sl_v v)
{
sl_process *proc = toprocess(v);
sl_print_str("#<process ", true);
sl_print(fixnum(proc->pid->pid));
sl_v state = proc->pid->state;
if(state != sl_nil){
sl_print_chr(' ');
sl_print(state);
if(state != runningsym && state != stoppedsym && proc->pid->code != 0){
sl_print_chr(' ');
sl_print(fixnum(proc->pid->code));
if(proc->pid->msg != nil){
sl_print_str(" \"", true);
sl_print_str(proc->pid->msg, false);
sl_print_chr('"');
if(proc->pid->dumped)
sl_print_str(" dumped", true);
}
}
}
sl_print_chr('>');
}
static void
relocate_process(sl_v oldv, sl_v newv)
{
sl_process *p = toprocess(newv);
for(int i = 0; i < nelem(p->stream); i++)
p->stream[i] = sl_relocate(p->stream[i]);
USED(oldv);
}
static void
free_process(sl_v self)
{
sl_process *proc = value2c(sl_process*, self);
sl_pid *p, *prev = nil;
for(p = slvm.pids; p != nil; prev = p, p = p->next){
if(p == proc->pid){
if(prev == nil)
slvm.pids = p->next;
else
prev->next = p->next;
break;
}
}
if(p == nil)
abort();
MEM_FREE(p->msg);
MEM_FREE(p);
proc->pid = nil;
}
BUILTIN("process-close", process_close)
{
argcount(1);
sl_process *proc = toprocess(args[0]);
for(int i = 0; i < nelem(proc->stream); i++){
if(isio(proc->stream[i]))
ios_close(value2c(ios*, proc->stream[i]));
}
return sl_void;
}
BUILTIN("process-post", process_post)
{
argcount(3);
sl_process *proc = toprocess(args[0]);
const char *note = tostr(args[1]);
const char *sig = tosym(args[2])->name;
return sys_postnote(proc->pid->pid, note, sig) == 0 ? sl_t : sl_nil;
}
static sl_cvtable process_vtable = {
print_process,
relocate_process,
free_process,
nil,
nil,
};
void
process_update(int pid, process_state_t state, int code, const char *msg)
{
for(sl_pid *p = slvm.pids; p != nil; p = p->next){
if(p->pid >= 0 && p->pid != pid)
continue;
switch(state){
case PSTATE_EXITED:
p->state = exitedsym;
break;
case PSTATE_STOPPED:
p->state = stoppedsym;
break;
case PSTATE_DUMPED:
p->dumped = true;
sl_fallthrough;
case PSTATE_SIGNALED:
p->state = signaledsym;
break;
case PSTATE_RUNNING:
p->state = runningsym;
break;
}
p->code = code;
p->msg = msg == nil ? nil : MEM_STRDUP(msg);
slvm.pidupdates++; // FIXME(sigrid): atomic
break;
}
// GC'ed - nobody cares anymore
}
void
process_init(void)
{
if((nullfd[0] = sys_open(SYS_DEV_NULL, IOS_READ, 0)) < 0)
sysfatal("%s", SYS_DEV_NULL);
if((nullfd[1] = nullfd[2] = sys_open(SYS_DEV_NULL, IOS_WRITE, 0)) < 0)
sysfatal("%s", SYS_DEV_NULL);
processtype = define_opaque_type(
mk_sym("process", false),
sizeof(sl_process),
&process_vtable,
nil
);
runningsym = mk_csym(":running");
exitedsym = mk_csym(":exited");
stoppedsym = mk_csym(":stopped");
signaledsym = mk_csym(":signaled");
insym = mk_csym(":in");
outsym = mk_csym(":out");
errsym = mk_csym(":err");
envsym = mk_csym(":env");
iosym = mk_csym(":io");
dirsym = mk_csym(":dir");
}