aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/app/process.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-21 16:00:31 +0900
committerOphestra <cat@gensokyo.uk>2025-02-21 16:06:24 +0900
commitc64b8163e79d47f1e710c1d067589bb393f8463c (patch)
treec4ffa5b89982af6362f1d65bf2ff2af299600574 /internal/app/process.go
parent9d9a165379798acb237c9071ea865f26cfba8be7 (diff)
app: separate instance from process state
This works better for the implementation. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/app/process.go')
-rw-r--r--internal/app/process.go56
1 files changed, 30 insertions, 26 deletions
diff --git a/internal/app/process.go b/internal/app/process.go
index c401eb37..1302d81a 100644
--- a/internal/app/process.go
+++ b/internal/app/process.go
@@ -20,12 +20,16 @@ import (
const shimSetupTimeout = 5 * time.Second
-func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
- a.mu.Lock()
- defer a.mu.Unlock()
+func (seal *outcome) Run(ctx context.Context, rs *fst.RunState) error {
+ if !seal.f.CompareAndSwap(false, true) {
+ // run does much more than just starting a process; calling it twice, even if the first call fails, will result
+ // in inconsistent state that is impossible to clean up; return here to limit damage and hopefully give the
+ // other Run a chance to return
+ panic("attempted to run twice")
+ }
if rs == nil {
- panic("attempted to pass nil state to run")
+ panic("invalid state")
}
/*
@@ -33,8 +37,8 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
*/
shimExec := [2]string{helper.BubblewrapName}
- if len(a.appSeal.command) > 0 {
- shimExec[1] = a.appSeal.command[0]
+ if len(seal.command) > 0 {
+ shimExec[1] = seal.command[0]
}
for i, n := range shimExec {
if len(n) == 0 {
@@ -54,15 +58,15 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
prepare/revert os state
*/
- if err := a.appSeal.sys.Commit(ctx); err != nil {
+ if err := seal.sys.Commit(ctx); err != nil {
return err
}
- store := state.NewMulti(a.sys.Paths().RunDirPath)
+ store := state.NewMulti(seal.runDirPath)
deferredStoreFunc := func(c state.Cursor) error { return nil }
defer func() {
var revertErr error
storeErr := new(StateStoreError)
- storeErr.Inner, storeErr.DoErr = store.Do(a.appSeal.user.aid.unwrap(), func(c state.Cursor) {
+ storeErr.Inner, storeErr.DoErr = store.Do(seal.user.aid.unwrap(), func(c state.Cursor) {
revertErr = func() error {
storeErr.InnerErr = deferredStoreFunc(c)
@@ -75,7 +79,7 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
ec.Set(system.Process)
if states, err := c.Load(); err != nil {
// revert per-process state here to limit damage
- return errors.Join(err, a.appSeal.sys.Revert(ec))
+ return errors.Join(err, seal.sys.Revert(ec))
} else {
if l := len(states); l == 0 {
fmsg.Verbose("no other launchers active, will clean up globals")
@@ -111,7 +115,7 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
}
}
- err := a.appSeal.sys.Revert(ec)
+ err := seal.sys.Revert(ec)
if err != nil {
err = err.(RevertCompoundError)
}
@@ -129,9 +133,9 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
waitErr := make(chan error, 1)
cmd := new(shim.Shim)
if startTime, err := cmd.Start(
- a.appSeal.user.aid.String(),
- a.appSeal.user.supp,
- a.appSeal.bwrapSync,
+ seal.user.aid.String(),
+ seal.user.supp,
+ seal.bwrapSync,
); err != nil {
return err
} else {
@@ -139,20 +143,20 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
rs.Time = startTime
}
- shimSetupCtx, shimSetupCancel := context.WithDeadline(ctx, time.Now().Add(shimSetupTimeout))
- defer shimSetupCancel()
+ c, cancel := context.WithTimeout(ctx, shimSetupTimeout)
+ defer cancel()
go func() {
waitErr <- cmd.Unwrap().Wait()
// cancel shim setup in case shim died before receiving payload
- shimSetupCancel()
+ cancel()
}()
- if err := cmd.Serve(shimSetupCtx, &shim.Payload{
- Argv: a.appSeal.command,
+ if err := cmd.Serve(c, &shim.Payload{
+ Argv: seal.command,
Exec: shimExec,
- Bwrap: a.appSeal.container,
- Home: a.appSeal.user.data,
+ Bwrap: seal.container,
+ Home: seal.user.data,
Verbose: fmsg.Load(),
}); err != nil {
@@ -161,14 +165,14 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
// shim accepted setup payload, create process state
sd := state.State{
- ID: a.id.unwrap(),
+ ID: seal.id.unwrap(),
PID: cmd.Unwrap().Process.Pid,
Time: *rs.Time,
}
var earlyStoreErr = new(StateStoreError) // returned after blocking on waitErr
- earlyStoreErr.Inner, earlyStoreErr.DoErr = store.Do(a.appSeal.user.aid.unwrap(), func(c state.Cursor) { earlyStoreErr.InnerErr = c.Save(&sd, a.appSeal.ct) })
+ earlyStoreErr.Inner, earlyStoreErr.DoErr = store.Do(seal.user.aid.unwrap(), func(c state.Cursor) { earlyStoreErr.InnerErr = c.Save(&sd, seal.ct) })
// destroy defunct state entry
- deferredStoreFunc = func(c state.Cursor) error { return c.Destroy(a.id.unwrap()) }
+ deferredStoreFunc = func(c state.Cursor) error { return c.Destroy(seal.id.unwrap()) }
select {
case err := <-waitErr: // block until fsu/shim returns
@@ -201,9 +205,9 @@ func (a *app) Run(ctx context.Context, rs *fst.RunState) error {
}
fmsg.Resume()
- if a.appSeal.dbusMsg != nil {
+ if seal.dbusMsg != nil {
// dump dbus message buffer
- a.appSeal.dbusMsg()
+ seal.dbusMsg()
}
return earlyStoreErr.equiv("cannot save process state:")