aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system/system.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/system/system.go')
-rw-r--r--internal/system/system.go53
1 files changed, 40 insertions, 13 deletions
diff --git a/internal/system/system.go b/internal/system/system.go
index 1462f818..340e23ec 100644
--- a/internal/system/system.go
+++ b/internal/system/system.go
@@ -6,7 +6,9 @@ import (
"errors"
"strings"
+ "hakurei.app/check"
"hakurei.app/hst"
+ "hakurei.app/internal/lockedfile"
"hakurei.app/message"
)
@@ -67,14 +69,6 @@ func TypeString(e hst.Enablements) string {
}
}
-// New returns the address of a new [I] targeting uid.
-func New(ctx context.Context, msg message.Msg, uid int) (sys *I) {
- if ctx == nil || msg == nil || uid < 0 {
- panic("invalid call to New")
- }
- return &I{ctx: ctx, msg: msg, uid: uid, syscallDispatcher: direct{}}
-}
-
// An I provides deferred operating system interaction. [I] must not be copied.
// Methods of [I] must not be used concurrently.
type I struct {
@@ -84,15 +78,32 @@ type I struct {
ops []Op
ctx context.Context
- // the behaviour of Commit is only defined for up to one call
- committed bool
- // the behaviour of Revert is only defined for up to one call
- reverted bool
+ // The behaviour of Commit and Revert is only defined for at most one call.
+ committed, reverted bool
+ // Optional Commit and Revert big lock.
+ mu *lockedfile.Mutex
msg message.Msg
syscallDispatcher
}
+// New returns the address of a new [I] targeting uid.
+func New(
+ ctx context.Context,
+ msg message.Msg,
+ uid int,
+ lock *check.Absolute,
+) (sys *I) {
+ if ctx == nil || msg == nil || uid < 0 {
+ panic("invalid call to New")
+ }
+ v := I{ctx: ctx, msg: msg, uid: uid, syscallDispatcher: direct{}}
+ if lock != nil {
+ v.mu = lockedfile.MutexAt(lock.String())
+ }
+ return &v
+}
+
func (sys *I) UID() int { return sys.uid }
// Equal returns whether all [Op] instances held by sys matches that of target.
@@ -118,9 +129,18 @@ func (sys *I) Commit() error {
if sys.committed {
panic("attempting to commit twice")
}
+
+ if sys.mu != nil {
+ if unlock, err := sys.mu.Lock(); err != nil {
+ return err
+ } else {
+ defer unlock()
+ }
+ }
sys.committed = true
- sp := New(sys.ctx, sys.msg, sys.uid)
+ sp := New(sys.ctx, sys.msg, sys.uid, nil)
+ // lock is still held on revert
sp.syscallDispatcher = sys.syscallDispatcher
sp.ops = make([]Op, 0, len(sys.ops)) // prevent copies during commits
defer func() {
@@ -153,6 +173,13 @@ func (sys *I) Revert(ec *Criteria) error {
if sys.reverted {
panic("attempting to revert twice")
}
+ if sys.mu != nil {
+ if unlock, err := sys.mu.Lock(); err != nil {
+ return err
+ } else {
+ defer unlock()
+ }
+ }
sys.reverted = true
// collect errors