Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions base/builtin/env.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,19 @@ extern char rts_exit;
extern int return_val;


// Env /////////////////////////////////////////////////////////////////////////
// Stdio ///////////////////////////////////////////////////////////////////////

$R B_EnvD_stdout_writeG_local (B_Env self, $Cont c$cont, B_str s) {
$R B_StdioD_outG_local (B_Stdio self, $Cont c$cont, B_str s) {
printf("%s", s->str);
return $R_CONT(c$cont, B_None);
}

$R B_EnvD_set_stdinG_local (B_Env self, $Cont c$cont, B_bool canonical, B_bool echo) {
$R B_StdioD_errG_local (B_Stdio self, $Cont c$cont, B_str s) {
fprintf(stderr, "%s", s->str);
return $R_CONT(c$cont, B_None);
}

$R B_StdioD_set_stdinG_local (B_Stdio self, $Cont c$cont, B_bool canonical, B_bool echo) {
#if defined(_WIN32) || defined(_WIN64)
#else
struct termios attr;
Expand Down Expand Up @@ -84,7 +89,7 @@ void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
}
}

$R B_EnvD__on_stdin_bytesG_local (B_Env self, $Cont c$cont, $action cb) {
$R B_StdioD__on_stdin_bytesG_local (B_Stdio self, $Cont c$cont, $action cb) {
// This should be the only call in env that does IO stuff, so it is safe to
// pin affinity here (and not earlier)..
pin_actor_affinity();
Expand All @@ -95,22 +100,19 @@ void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
return $R_CONT(c$cont, B_None);
}


// Env /////////////////////////////////////////////////////////////////////////

$R B_EnvD_exitG_local (B_Env self, $Cont c$cont, B_int n) {
return_val = fromB_int(n);
rts_shutdown();
return $R_CONT(c$cont, B_None);
}


B_Env B_EnvG_newactor(B_WorldCap wc, B_SysCap sc, B_list args) {
B_Env B_EnvG_newactor() {
B_Env $tmp = $NEWACTOR(B_Env);
$tmp->cap = wc;
$tmp->args = args;
$tmp->syscap = sc;
$tmp->auth = $tmp->cap;
$tmp->argv = $tmp->args;
$tmp->$affinity = 0; // hard-coded to special worker on the main thread
serialize_state_shortcut(($Actor)$tmp);
return $tmp;
}

Expand Down Expand Up @@ -138,3 +140,14 @@ B_NoneType B_WorldCapD___init__ (B_WorldCap self) {
return B_None;
}


B_EnvCap B_EnvCapG_new() {
B_EnvCap $tmp = acton_malloc(sizeof(struct B_EnvCap));
$tmp->$class = &B_EnvCapG_methods;
// B_EnvCapG_methods.__init__($tmp);
return $tmp;
}

B_NoneType B_EnvCapD___init__ (B_EnvCap self) {
return B_None;
}
5 changes: 4 additions & 1 deletion base/builtin/env.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#pragma once

B_Env B_EnvG_newactor (B_WorldCap, B_SysCap, B_list);
B_Env B_EnvG_newactor ();

B_SysCap B_SysCapG_new();
B_NoneType B_SysCapD___init__ (B_SysCap self);

B_WorldCap B_WorldCapG_new();
B_NoneType B_WorldCapD___init__ (B_WorldCap self);

B_EnvCap B_EnvCapG_new();
B_NoneType B_EnvCapD___init__ (B_EnvCap self);
78 changes: 69 additions & 9 deletions base/rts/rts.c
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ struct $Cont $Fail$instance = {
&$FailG_methods
};
////////////////////////////////////////////////////////////////////////////////////////

$R $InitRootD___call__ ($Cont $this, $WORD val) {
typedef $R(*ROOT__init__t)($Actor, $Cont, B_Env); // Assumed type of the ROOT actor's __init__ method
return ((ROOT__init__t)root_actor->$class->__init__)(root_actor, ($Cont)val, env_actor);
Expand All @@ -739,6 +740,56 @@ struct $ContG_class $InitRootG_methods = {
struct $Cont $InitRoot$cont = {
&$InitRootG_methods
};

$R $StartRootD___call__ ($Cont $this, $WORD val) {
// Env.__init__ has completed here; now preserve Env and start root init.
serialize_state_shortcut(($Actor)env_actor);
$ASYNC(root_actor, &$InitRoot$cont);
return $R_DONE(val);
}

struct $ContG_class $StartRootG_methods = {
"$StartRoot",
UNASSIGNED,
NULL,
$ContD___init__,
$ContD___serialize__,
$ContD___deserialize__,
$ContD___bool__,
$ContD___str__,
$ContD___str__,
$StartRootD___call__
};
struct $Cont $StartRoot$cont = {
&$StartRootG_methods
};

$R $InitEnvD___call__ ($Cont $this, $WORD val) {
typedef $R(*ENV__init__t)(B_Env, $Cont, B_WorldCap, B_SysCap, B_list, B_int, B_EnvCap);
B_tuple init = (B_tuple)val;
B_WorldCap wc = (B_WorldCap)init->components[0];
B_SysCap sc = (B_SysCap)init->components[1];
B_list args = (B_list)init->components[2];
B_int nr_wthreads = (B_int)init->components[3];
B_EnvCap envcap = (B_EnvCap)init->components[4];
return ((ENV__init__t)env_actor->$class->__init__)(env_actor, &$StartRoot$cont, wc, sc, args, nr_wthreads, envcap);
}

struct $ContG_class $InitEnvG_methods = {
"$InitEnv",
UNASSIGNED,
NULL,
$ContD___init__,
$ContD___serialize__,
$ContD___deserialize__,
$ContD___bool__,
$ContD___str__,
$ContD___str__,
$InitEnvD___call__
};
struct $Cont $InitEnv$cont = {
&$InitEnvG_methods
};
////////////////////////////////////////////////////////////////////////////////////////

#ifdef ACTON_DB
Expand Down Expand Up @@ -1402,25 +1453,32 @@ void BOOTSTRAP(int argc, char *argv[]) {
for (int i=0; i< argc; i++)
wit->$class->append(wit,args,to$str(argv[i]));

env_actor = B_EnvG_newactor(B_WorldCapG_new(), B_SysCapG_new(), args);
env_actor->nr_wthreads = toB_int(num_wthreads);

env_actor = B_EnvG_newactor();
root_actor = $ROOT(); // Assumed to return $NEWACTOR(X) for the selected root actor X

// Bootstrap targets Env first. $InitEnv runs Env.__init__ with
// $StartRoot$cont, which schedules root init after Env is initialized.
B_tuple env_init = $NEWTUPLE(5,
B_WorldCapG_new(),
B_SysCapG_new(),
args,
toB_int(num_wthreads),
B_EnvCapG_new());
time_t now = current_time();
B_Msg m = B_MsgG_newXX(root_actor, &$InitRoot$cont, now, &$Done$instance);
B_Msg m = B_MsgG_newXX(($Actor)env_actor, &$InitEnv$cont, now, env_init);
#ifdef ACTON_DB
if (db) {
int ret = 0, minority_status = 0;
while(!rts_exit) {
ret = remote_enqueue_in_txn(($WORD*)&m->$globkey, 1, NULL, 0, MSG_QUEUE, (WORD)root_actor->$globkey, &minority_status, NULL, db);
rtsd_printf(" # enqueue bootstrap msg %ld to root actor queue %ld returns %d, minority_status %d", m->$globkey, root_actor->$globkey, ret, minority_status);
if(!handle_status_and_schema_mismatch(ret, minority_status, root_actor->$globkey))
ret = remote_enqueue_in_txn(($WORD*)&m->$globkey, 1, NULL, 0, MSG_QUEUE, (WORD)env_actor->$globkey, &minority_status, NULL, db);
rtsd_printf(" # enqueue bootstrap msg %ld to env actor queue %ld returns %d, minority_status %d", m->$globkey, env_actor->$globkey, ret, minority_status);
if(!handle_status_and_schema_mismatch(ret, minority_status, env_actor->$globkey))
break;
}
}
#endif
if (ENQ_msg(m, root_actor)) {
ENQ_ready(root_actor);
if (ENQ_msg(m, ($Actor)env_actor)) {
ENQ_ready(($Actor)env_actor);
}

}
Expand Down Expand Up @@ -1774,6 +1832,8 @@ void $register_rts () {
$register(&$DoneG_methods);
$register(&$InitRootG_methods);
$register(&B_EnvG_methods);
$register(&$StartRootG_methods);
$register(&$InitEnvG_methods);
}

////////////////////////////////////////////////////////////////////////////////////////
Expand Down
68 changes: 60 additions & 8 deletions base/src/__builtin__.act
Original file line number Diff line number Diff line change
Expand Up @@ -1122,13 +1122,12 @@ class SysCap():
"""
pass

actor Env (wc: WorldCap, sc: SysCap, args: list[str]):
cap = wc
auth = wc
syscap = sc
argv = args
nr_wthreads: int = 0
class EnvCap():
"""EnvCap authorizes construction of Env-owned service actors.
"""
pass

actor EnvVar(envcap: EnvCap):
action def getenv(name: str) -> ?str:
"""Get the value of an environment variable"""
res = getenvb(name.encode())
Expand Down Expand Up @@ -1156,7 +1155,11 @@ actor Env (wc: WorldCap, sc: SysCap, args: list[str]):
"""Unset an environment variable"""
NotImplemented

action def stdout_write(s: str) -> None:
actor Stdio(envcap: EnvCap, vars: EnvVar):
action def out(s: str) -> None:
NotImplemented

action def err(s: str) -> None:
NotImplemented

action def stdin_install(on_stdin: ?action(str) -> None, encoding: ?str=None, on_error: ?action(str, bytes) -> None, on_stdin_bytes: ?action(bytes) -> None) -> None:
Expand All @@ -1174,7 +1177,7 @@ actor Env (wc: WorldCap, sc: SysCap, args: list[str]):
# Default to utf-8 if we're unable to discover the encoding
encoding = "utf-8"
# Read encoding from the LANG environment variable
lang_env = getenv("LANG")
lang_env = vars.getenv("LANG")
if lang_env is not None:
try:
encoding = lang_env.split(".")[1].lower()
Expand All @@ -1195,5 +1198,54 @@ actor Env (wc: WorldCap, sc: SysCap, args: list[str]):
action def _on_stdin_bytes(cb: action(bytes) -> None) -> None:
NotImplemented

def _new_vars(envcap: EnvCap):
return EnvVar(envcap)

actor Env (wc: WorldCap, sc: SysCap, args: list[str], wthreads: int, envcap: EnvCap):
cap = wc
auth = wc
syscap = sc
argv = args
nr_wthreads = wthreads
vars = _new_vars(envcap)

action def getenv(name: str) -> ?str:
"""Get the value of an environment variable"""
return vars.getenv(name)

action def getenvb(name: bytes) -> ?bytes:
"""Get the value of an environment variable"""
return vars.getenvb(name)

action def setenv(n: str, v: str) -> None:
"""Set the value of an environment variable"""
vars.setenv(n, v)

action def setenvb(n: bytes, v: bytes) -> None:
"""Set the value of an environment variable"""
vars.setenvb(n, v)

action def unsetenv(n: str) -> None:
"""Unset an environment variable"""
vars.unsetenv(n)

action def unsetenvb(n: bytes) -> None:
"""Unset an environment variable"""
vars.unsetenvb(n)

stdio = Stdio(envcap, vars)

action def stdout_write(s: str) -> None:
stdio.out(s)
Comment thread
plajjan marked this conversation as resolved.

action def stdin_install(on_stdin: ?action(str) -> None, encoding: ?str=None, on_error: ?action(str, bytes) -> None, on_stdin_bytes: ?action(bytes) -> None) -> None:
stdio.stdin_install(on_stdin, encoding, on_error, on_stdin_bytes)

action def set_stdin(canonical: ?bool, echo: ?bool) -> None:
stdio.set_stdin(canonical, echo)

action def is_tty() -> bool:
return stdio.is_tty()

action def exit(n: int):
NotImplemented
10 changes: 5 additions & 5 deletions base/src/__builtin__.ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ B_str B_type(B_value a) {
return to$str("None");
}

$R B_EnvD_getenvbG_local (B_Env self, $Cont C_cont, B_bytes name) {
// uv_os_getenv is not threadsafe but our Env actor forces serial execution
$R B_EnvVarD_getenvbG_local (B_EnvVar self, $Cont C_cont, B_bytes name) {
// uv_os_getenv is not threadsafe but our EnvVar actor forces serial execution

// Try to use a small fixed size buffer
size_t len = 256;
Expand All @@ -55,7 +55,7 @@ B_str B_type(B_value a) {
return $R_CONT(C_cont, to$bytes(value));
}

$R B_EnvD_setenvbG_local (B_Env self, $Cont C_cont, B_bytes name, B_bytes value) {
$R B_EnvVarD_setenvbG_local (B_EnvVar self, $Cont C_cont, B_bytes name, B_bytes value) {
const char* env_var = fromB_bytes(name);
const char* env_val = fromB_bytes(value);
int r = uv_os_setenv(env_var, env_val);
Expand All @@ -65,7 +65,7 @@ B_str B_type(B_value a) {
return $R_CONT(C_cont, B_None);
}

$R B_EnvD_unsetenvbG_local (B_Env self, $Cont C_cont, B_bytes name) {
$R B_EnvVarD_unsetenvbG_local (B_EnvVar self, $Cont C_cont, B_bytes name) {
const char* env_var = fromB_bytes(name);
int r = uv_os_unsetenv(env_var);
if (r < 0) {
Expand All @@ -75,7 +75,7 @@ B_str B_type(B_value a) {
}

// action def is_tty() -> bool:
$R B_EnvD_is_ttyG_local (B_Env self, $Cont C_cont) {
$R B_StdioD_is_ttyG_local (B_Stdio self, $Cont C_cont) {
return $R_CONT(C_cont, toB_bool(isatty(1)));
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/acton/test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@ rtsTests =
(returnCode, cmdOut, cmdErr) <- runThing "--rts-wthreads" "../../test/rts/argv7.act"
assertEqual "RTS wthreads error retCode" (ExitFailure 1) returnCode
assertEqual "RTS wthreads error cmdErr" "ERROR: --rts-wthreads requires an argument.\n" cmdErr

, testCase "Env init starts root actor with initialized Env and service actors" $ do
testBuildAndRun "" "--rts-wthreads=7" ExitSuccess False "../../test/rts/env_init.act"
]

stdlibTests =
Expand Down
4 changes: 4 additions & 0 deletions test/core_lang_auto/envcap__bf.act
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# It should not be possible to forge EnvCap to construct Env-owned services.

actor main(env):
stdio = Stdio(EnvCap(), env.vars)
14 changes: 14 additions & 0 deletions test/rts/env_init.act
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
actor main(env):
# main only runs if the Env bootstrap continuation starts root init.
env.vars.setenv("ACTON_ENV_INIT_TEST", "ok")
env.stdio.out("")
env.stdio.err("")
if env.nr_wthreads != 7:
env.exit(1)
elif env.vars.getenv("ACTON_ENV_INIT_TEST") != "ok":
env.exit(1)
elif env.getenv("ACTON_ENV_INIT_TEST") != "ok":
env.exit(1)
else:
env.vars.unsetenv("ACTON_ENV_INIT_TEST")
env.exit(0)