Task 5: goroutine-safe Register, preserve loop result, remove placeholder
- internal/capi/register.go: Use sync.Once for goroutine-safe initialization - pipewire/interfaces.go: MainLoop.Run() now returns int32 - pipewire/runtime.go: wrapper returns inner.Run() result - pipewire/loop.go: Removed empty placeholder file
- commit
- f5674163744591ed220f2712c3b096d8ea529b7f
- author
- brice · · 2026-04-09 06:29 UTC
- parent
- 7d5e644
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +21 -22
M internal/capi/register.go +18 -15
| @@ -1,6 +1,7 @@ | |||
| 1 | 1 | package capi | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "sync" | |
| 4 | 5 | "unsafe" | |
| 5 | 6 | ||
| 6 | 7 | "github.com/bnema/purego-pipewire/internal/loader" | |
| @@ -31,25 +32,27 @@ func (d defaultImpl) PWMainLoopRun(loop unsafe.Pointer) int32 { | |||
| 31 | 32 | } | |
| 32 | 33 | ||
| 33 | 34 | var ( | |
| 34 | - | defaultAPI portout.CAPI | |
| 35 | - | registered bool | |
| 35 | + | defaultAPI portout.CAPI | |
| 36 | + | registerOnce sync.Once | |
| 37 | + | registerErr error | |
| 36 | 38 | ) | |
| 37 | 39 | ||
| 38 | 40 | // Register loads the PipeWire libraries and registers all function bindings. | |
| 41 | + | // It is safe to call from multiple goroutines; the initialization will only happen once. | |
| 39 | 42 | func Register() error { | |
| 40 | - | if registered { | |
| 41 | - | return nil | |
| 42 | - | } | |
| 43 | - | h, err := loader.Open() | |
| 44 | - | if err != nil { | |
| 45 | - | return err | |
| 46 | - | } | |
| 47 | - | if err := registerAll(h); err != nil { | |
| 48 | - | return err | |
| 49 | - | } | |
| 50 | - | defaultAPI = defaultImpl{} | |
| 51 | - | registered = true | |
| 52 | - | return nil | |
| 43 | + | registerOnce.Do(func() { | |
| 44 | + | h, err := loader.Open() | |
| 45 | + | if err != nil { | |
| 46 | + | registerErr = err | |
| 47 | + | return | |
| 48 | + | } | |
| 49 | + | if err := registerAll(h); err != nil { | |
| 50 | + | registerErr = err | |
| 51 | + | return | |
| 52 | + | } | |
| 53 | + | defaultAPI = defaultImpl{} | |
| 54 | + | }) | |
| 55 | + | return registerErr | |
| 53 | 56 | } | |
| 54 | 57 | ||
| 55 | 58 | // Default returns the default CAPI instance after Register() has been called. | |
| @@ -1,6 +1,7 @@ | |||||
| 1 | package capi | 1 | package capi | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "sync" | |||
| 4 | "unsafe" | 5 | "unsafe" | ||
| 5 | 6 | ||||
| 6 | "github.com/bnema/purego-pipewire/internal/loader" | 7 | "github.com/bnema/purego-pipewire/internal/loader" | ||
| @@ -31,25 +32,27 @@ func (d defaultImpl) PWMainLoopRun(loop unsafe.Pointer) int32 { | |||||
| 31 | } | 32 | } | ||
| 32 | 33 | ||||
| 33 | var ( | 34 | var ( | ||
| 34 | - | defaultAPI portout.CAPI | 35 | + | defaultAPI portout.CAPI |
| 35 | - | registered bool | 36 | + | registerOnce sync.Once |
| 37 | + | registerErr error | |||
| 36 | ) | 38 | ) | ||
| 37 | 39 | ||||
| 38 | // Register loads the PipeWire libraries and registers all function bindings. | 40 | // Register loads the PipeWire libraries and registers all function bindings. | ||
| 41 | + | // It is safe to call from multiple goroutines; the initialization will only happen once. | |||
| 39 | func Register() error { | 42 | func Register() error { | ||
| 40 | - | if registered { | 43 | + | registerOnce.Do(func() { |
| 41 | - | return nil | 44 | + | h, err := loader.Open() |
| 42 | - | } | 45 | + | if err != nil { |
| 43 | - | h, err := loader.Open() | 46 | + | registerErr = err |
| 44 | - | if err != nil { | 47 | + | return |
| 45 | - | return err | 48 | + | } |
| 46 | - | } | 49 | + | if err := registerAll(h); err != nil { |
| 47 | - | if err := registerAll(h); err != nil { | 50 | + | registerErr = err |
| 48 | - | return err | 51 | + | return |
| 49 | - | } | 52 | + | } |
| 50 | - | defaultAPI = defaultImpl{} | 53 | + | defaultAPI = defaultImpl{} |
| 51 | - | registered = true | 54 | + | }) |
| 52 | - | return nil | 55 | + | return registerErr |
| 53 | } | 56 | } | ||
| 54 | 57 | ||||
| 55 | // Default returns the default CAPI instance after Register() has been called. | 58 | // Default returns the default CAPI instance after Register() has been called. | ||
M pipewire/interfaces.go +1 -1
| @@ -9,6 +9,6 @@ type Runtime interface { | |||
| 9 | 9 | ||
| 10 | 10 | // MainLoop is the public interface for PipeWire main loop operations. | |
| 11 | 11 | type MainLoop interface { | |
| 12 | - | Run() | |
| 12 | + | Run() int32 | |
| 13 | 13 | Destroy() | |
| 14 | 14 | } | |
| @@ -9,6 +9,6 @@ type Runtime interface { | |||||
| 9 | 9 | ||||
| 10 | // MainLoop is the public interface for PipeWire main loop operations. | 10 | // MainLoop is the public interface for PipeWire main loop operations. | ||
| 11 | type MainLoop interface { | 11 | type MainLoop interface { | ||
| 12 | - | Run() | 12 | + | Run() int32 |
| 13 | Destroy() | 13 | Destroy() | ||
| 14 | } | 14 | } | ||
D pipewire/loop.go +0 -4
| @@ -1,4 +0,0 @@ | |||
| 1 | - | package pipewire | |
| 2 | - | ||
| 3 | - | // Loop provides additional main loop related types and constants. | |
| 4 | - | // This file exists for future loop-related public API expansion. | |
| @@ -1,4 +0,0 @@ | |||||
| 1 | - | package pipewire | |||
| 2 | - | ||||
| 3 | - | // Loop provides additional main loop related types and constants. | |||
| 4 | - | // This file exists for future loop-related public API expansion. | |||
M pipewire/runtime.go +2 -2
| @@ -33,8 +33,8 @@ type mainLoopWrapper struct { | |||
| 33 | 33 | inner *core.MainLoop | |
| 34 | 34 | } | |
| 35 | 35 | ||
| 36 | - | func (mlw mainLoopWrapper) Run() { | |
| 37 | - | mlw.inner.Run() | |
| 36 | + | func (mlw mainLoopWrapper) Run() int32 { | |
| 37 | + | return mlw.inner.Run() | |
| 38 | 38 | } | |
| 39 | 39 | ||
| 40 | 40 | func (mlw mainLoopWrapper) Destroy() { | |
| @@ -33,8 +33,8 @@ type mainLoopWrapper struct { | |||||
| 33 | inner *core.MainLoop | 33 | inner *core.MainLoop | ||
| 34 | } | 34 | } | ||
| 35 | 35 | ||||
| 36 | - | func (mlw mainLoopWrapper) Run() { | 36 | + | func (mlw mainLoopWrapper) Run() int32 { |
| 37 | - | mlw.inner.Run() | 37 | + | return mlw.inner.Run() |
| 38 | } | 38 | } | ||
| 39 | 39 | ||||
| 40 | func (mlw mainLoopWrapper) Destroy() { | 40 | func (mlw mainLoopWrapper) Destroy() { | ||