diff options
Diffstat (limited to 'internal/system/system.go')
| -rw-r--r-- | internal/system/system.go | 53 |
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 |
