aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-05-27 17:58:01 +0900
committerOphestra <cat@gensokyo.uk>2026-05-27 17:58:01 +0900
commitb18f40d974ffc33f3703d46bfe42d6fa2f844a01 (patch)
tree1b713d0d797ab99da540d772255009775fe3c1c3
parent12a606105124d1ef3133594afb9e6e0bc2e0ad33 (diff)
internal/kobject: pass action kind for range
Useful for handling most uevents. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--cmd/earlyinit/main.go8
-rw-r--r--cmd/earlyinit/mount.go6
-rw-r--r--cmd/earlyinit/uevent.go5
-rw-r--r--internal/kobject/kobject.go33
-rw-r--r--internal/kobject/kobject_test.go12
5 files changed, 41 insertions, 23 deletions
diff --git a/cmd/earlyinit/main.go b/cmd/earlyinit/main.go
index df454e3d..b5e8bcde 100644
--- a/cmd/earlyinit/main.go
+++ b/cmd/earlyinit/main.go
@@ -19,6 +19,7 @@ import (
"hakurei.app/internal/kobject"
"hakurei.app/internal/report"
"hakurei.app/internal/uevent"
+ "hakurei.app/message"
)
var r report.Reporter
@@ -79,6 +80,8 @@ const (
// optionSystem specifies devpath of the system device.
optionSystem = "system"
+ // flagVerbose increases output verbosity.
+ flagVerbose = "verbose"
// flagStrict sets [report.DStrict] on r.
flagStrict = "strict"
// flagNoRecover sets [report.DNoRecover] on r.
@@ -116,6 +119,9 @@ func main() {
r.SetFlags(flag)
}
+ msg := message.New(log.Default())
+ msg.SwapVerbose(slices.Contains(flags, flagVerbose))
+
mustSyscall("mount devtmpfs", Mount(
"devtmpfs",
"/dev/",
@@ -193,7 +199,7 @@ func main() {
must1(rand.Read(uuid[:]))
ctx, cancel := context.WithCancel(context.Background())
- go consume(ctx, &r, conn, uuid, events)
+ go consume(ctx, msg, &r, conn, uuid, events)
s := kobject.New(uuid, func(o *kobject.Object, env map[string]string) {
log.Printf("change %s: %q", o.DevPath, env)
}, func(err error) {
diff --git a/cmd/earlyinit/mount.go b/cmd/earlyinit/mount.go
index 6ac59a46..51d4ecc9 100644
--- a/cmd/earlyinit/mount.go
+++ b/cmd/earlyinit/mount.go
@@ -12,6 +12,7 @@ import (
"hakurei.app/check"
"hakurei.app/fhs"
"hakurei.app/internal/kobject"
+ "hakurei.app/internal/uevent"
)
// mustMountSystem waits for and mounts a system device matching pattern.
@@ -26,8 +27,9 @@ func mustMountSystem(
for {
var matchErr error
var systemPath *check.Absolute
- s.Range(c, func(o *kobject.Object) bool {
- if o.Subsystem != "block" ||
+ s.Range(c, func(o *kobject.Object, act uevent.KobjectAction) bool {
+ if (act != uevent.KOBJ_ADD && act != uevent.KOBJ_CHANGE) ||
+ o.Subsystem != "block" ||
o.Env["DEVTYPE"] != "disk" {
return true
}
diff --git a/cmd/earlyinit/uevent.go b/cmd/earlyinit/uevent.go
index 0ab134cf..64f548ba 100644
--- a/cmd/earlyinit/uevent.go
+++ b/cmd/earlyinit/uevent.go
@@ -2,12 +2,12 @@ package main
import (
"context"
- "log"
"time"
"hakurei.app/fhs"
"hakurei.app/internal/report"
"hakurei.app/internal/uevent"
+ "hakurei.app/message"
)
// newRejectColdboot returns a function to be called on every subsequent pending
@@ -56,6 +56,7 @@ func newRejectColdboot() func() bool {
// consume continuously consumes events from conn with retries.
func consume(
ctx context.Context,
+ msg message.Msg,
r *report.Reporter,
conn *uevent.Conn,
uuid uevent.UUID,
@@ -67,7 +68,7 @@ func consume(
coldboot := true
retry:
if dispatchErr := conn.Consume(ctx, fhs.Sys, &uuid, events, coldboot, func(path string) {
- log.Println("coldboot visited", path)
+ msg.Verbose("coldboot visited", path)
}, func(err error) bool {
if _, ok := err.(uevent.NeedsColdboot); ok && !nextColdboot() {
r.Dispatch(
diff --git a/internal/kobject/kobject.go b/internal/kobject/kobject.go
index 26359114..2acf3de0 100644
--- a/internal/kobject/kobject.go
+++ b/internal/kobject/kobject.go
@@ -101,7 +101,7 @@ func (o *Object) update(env map[string]string, strip bool) {
// A pendingIterator is a callback currently iterating through objects targeted
// by ongoing events.
type pendingIterator struct {
- f func(o *Object) bool
+ f func(o *Object, act uevent.KobjectAction) bool
done chan<- struct{}
}
@@ -150,12 +150,12 @@ func (s *State) deleteIter(p *pendingIterator) {
}
// dispatchIter broadcasts an [Object] to all alive iterators.
-func (s *State) dispatchIter(o *Object) {
+func (s *State) dispatchIter(o *Object, act uevent.KobjectAction) {
s.iterMu.Lock()
defer s.iterMu.Unlock()
for _, p := range s.iter {
- if !p.f(o) {
+ if !p.f(o, act) {
s.deleteIter(p)
close(p.done)
}
@@ -165,14 +165,17 @@ func (s *State) dispatchIter(o *Object) {
// Range calls f on all current and upcoming [Object] values tracked by s until
// f returns false or the context is cancelled. f must not retain o or modify
// the value it points to.
-func (s *State) Range(ctx context.Context, f func(o *Object) bool) {
+func (s *State) Range(
+ ctx context.Context,
+ f func(o *Object, act uevent.KobjectAction) bool,
+) {
done := make(chan struct{})
p := pendingIterator{f, done}
s.iterMu.Lock()
s.ueventMu.RLock()
for _, o := range s.uevent {
- if !f(o) {
+ if !f(o, uevent.KOBJ_ADD) {
s.ueventMu.RUnlock()
s.iterMu.Unlock()
return
@@ -296,13 +299,13 @@ func (s *State) processEvent(e *Event) {
return
}
- switch e.Action {
+ switch act := e.Action; act {
case uevent.KOBJ_ADD:
if e.Synth == nil {
if o, ok := s.uevent[e.DevPath]; ok {
s.reportErr(e.NewError(EDuplicateAdd, o))
o.merge(e.Env)
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
}
}
@@ -312,7 +315,7 @@ func (s *State) processEvent(e *Event) {
}
o.merge(e.Env)
s.uevent[e.DevPath] = o
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
case uevent.KOBJ_REMOVE:
@@ -338,14 +341,14 @@ func (s *State) processEvent(e *Event) {
o = e.makeColdboot()
o.merge(e.Env)
s.uevent[e.DevPath] = o
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
}
o.update(e.Env, true)
if s.handleChange != nil {
s.handleChange(o, e.Env)
}
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
case uevent.KOBJ_MOVE:
@@ -368,7 +371,7 @@ func (s *State) processEvent(e *Event) {
o.merge(e.Env)
s.uevent[e.DevPath] = o
o.DevPath = e.DevPath
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
case uevent.KOBJ_ONLINE:
@@ -384,7 +387,7 @@ func (s *State) processEvent(e *Event) {
s.reportErr(e.NewError(EUnexpectedOffline, o))
}
o.Offline = false
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
case uevent.KOBJ_OFFLINE:
@@ -400,7 +403,7 @@ func (s *State) processEvent(e *Event) {
s.reportErr(e.NewError(EUnexpectedOffline, o))
}
o.Offline = true
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
case uevent.KOBJ_BIND:
@@ -416,7 +419,7 @@ func (s *State) processEvent(e *Event) {
}
o.State = StateBound
o.merge(e.Env)
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
case uevent.KOBJ_UNBIND:
@@ -432,7 +435,7 @@ func (s *State) processEvent(e *Event) {
}
o.State = StateNew
o.Driver = ""
- s.dispatchIter(o)
+ s.dispatchIter(o, act)
return
default: // not reached
diff --git a/internal/kobject/kobject_test.go b/internal/kobject/kobject_test.go
index b184e621..c6a54904 100644
--- a/internal/kobject/kobject_test.go
+++ b/internal/kobject/kobject_test.go
@@ -388,7 +388,9 @@ func TestIter(t *testing.T) {
"SEQNUM=1",
}}
synctest.Wait()
- s.Range(t.Context(), func(o *Object) bool { return false })
+ s.Range(t.Context(), func(*Object, uevent.KobjectAction) bool {
+ return false
+ })
var got []*Object
check := func(want []*Object) {
@@ -405,7 +407,7 @@ func TestIter(t *testing.T) {
defer cancel()
var done bool
wg.Go(func() {
- s.Range(ctx, func(o *Object) bool {
+ s.Range(ctx, func(o *Object, _ uevent.KobjectAction) bool {
got = append(got, o.Clone())
return !done
})
@@ -437,7 +439,11 @@ func TestIter(t *testing.T) {
},
})
- wg.Go(func() { s.Range(ctx, func(*Object) bool { return true }) })
+ wg.Go(func() {
+ s.Range(ctx, func(*Object, uevent.KobjectAction) bool {
+ return true
+ })
+ })
synctest.Wait()
iter := reflect.ValueOf(s).Elem().FieldByName("iter")