Skip to content

Commit 0c39b47

Browse files
xaionaro@dx.centerxaionaro@dx.center
authored andcommitted
fix: extract closure-wrapped mutex patterns into named functions
1 parent b2c3593 commit 0c39b47

4 files changed

Lines changed: 89 additions & 68 deletions

File tree

examples/alarm/main.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,24 +127,12 @@ func run(vm *jni.VM, output *bytes.Buffer) error {
127127
go func() {
128128
time.Sleep(delay)
129129
if err := postNotification(vm, appCtxObj); err != nil {
130-
func() {
131-
ui.OutputMu.Lock()
132-
defer ui.OutputMu.Unlock()
133-
fmt.Fprintf(output, "notification error: %v\n", err)
134-
}()
130+
ui.FormatToOutputBuf("notification error: %v\n", err)
135131
}
136132
if err := playAlarmRingtone(vm, appCtxObj); err != nil {
137-
func() {
138-
ui.OutputMu.Lock()
139-
defer ui.OutputMu.Unlock()
140-
fmt.Fprintf(output, "ringtone error: %v\n", err)
141-
}()
133+
ui.FormatToOutputBuf("ringtone error: %v\n", err)
142134
}
143-
func() {
144-
ui.OutputMu.Lock()
145-
defer ui.OutputMu.Unlock()
146-
fmt.Fprintf(output, "alarm fired!\n")
147-
}()
135+
ui.FormatToOutputBuf("alarm fired!\n")
148136
ui.RenderOutput()
149137
}()
150138

examples/common/ui/ui.go

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,54 @@ func Register(fn RunFunc) {
8383
runFunc = fn
8484
}
8585

86+
// resetOutputBuf clears the shared output buffer.
87+
func resetOutputBuf() {
88+
OutputMu.Lock()
89+
defer OutputMu.Unlock()
90+
outputBuf.Reset()
91+
}
92+
93+
// appendToOutputBuf writes data into the shared output buffer.
94+
func appendToOutputBuf(data []byte) {
95+
OutputMu.Lock()
96+
defer OutputMu.Unlock()
97+
outputBuf.Write(data)
98+
}
99+
100+
// FormatToOutputBuf formats and writes a message into the shared output buffer.
101+
func FormatToOutputBuf(format string, args ...any) {
102+
OutputMu.Lock()
103+
defer OutputMu.Unlock()
104+
fmt.Fprintf(&outputBuf, format, args...)
105+
}
106+
107+
// snapshotOutputBuf returns a copy of the current output buffer contents.
108+
func snapshotOutputBuf() string {
109+
OutputMu.Lock()
110+
defer OutputMu.Unlock()
111+
return outputBuf.String()
112+
}
113+
114+
// snapshotOutputBufIfNonEmpty returns the buffer contents and whether the
115+
// buffer was non-empty, under a single lock acquisition.
116+
func snapshotOutputBufIfNonEmpty() (text string, nonEmpty bool) {
117+
OutputMu.Lock()
118+
defer OutputMu.Unlock()
119+
nonEmpty = outputBuf.Len() > 0
120+
if nonEmpty {
121+
text = outputBuf.String()
122+
}
123+
return text, nonEmpty
124+
}
125+
86126
// OnCreate is called when the NativeActivity is created.
87127
func OnCreate(
88128
cvm *jni.VM,
89129
activity *jni.Object,
90130
) {
91131
vm = cvm
92132
activityRef = activity
93-
func() {
94-
OutputMu.Lock()
95-
defer OutputMu.Unlock()
96-
outputBuf.Reset()
97-
}()
133+
resetOutputBuf()
98134
exampleStarted = false
99135
}
100136

@@ -117,11 +153,7 @@ func OnNativeWindowCreated(windowPtr unsafe.Pointer) {
117153
var err error
118154
needed, err = getUngrantedPermissions(env, activityRef)
119155
if err != nil {
120-
func() {
121-
OutputMu.Lock()
122-
defer OutputMu.Unlock()
123-
fmt.Fprintf(&outputBuf, "permissions check: %v\n", err)
124-
}()
156+
FormatToOutputBuf("permissions check: %v\n", err)
125157
}
126158
return nil
127159
})
@@ -151,11 +183,7 @@ func startExample() {
151183
if err := runFunc(vm, &localBuf); err != nil {
152184
fmt.Fprintf(&localBuf, "ERROR: %v\n", err)
153185
}
154-
func() {
155-
OutputMu.Lock()
156-
defer OutputMu.Unlock()
157-
outputBuf.Write(localBuf.Bytes())
158-
}()
186+
appendToOutputBuf(localBuf.Bytes())
159187
}
160188
RenderOutput()
161189
}()
@@ -164,11 +192,7 @@ func startExample() {
164192
// RenderOutput re-renders the current output buffer to the screen.
165193
// Call from background goroutines after appending to the shared buffer.
166194
func RenderOutput() {
167-
text := func() string {
168-
OutputMu.Lock()
169-
defer OutputMu.Unlock()
170-
return outputBuf.String()
171-
}()
195+
text := snapshotOutputBuf()
172196
if text == "" {
173197
text = "(no output)"
174198
}
@@ -177,16 +201,7 @@ func RenderOutput() {
177201

178202
// OnResume is called when the activity resumes (e.g. after permission dialog).
179203
func OnResume(activity *jni.Object) {
180-
hasOutput, text := func() (bool, string) {
181-
OutputMu.Lock()
182-
defer OutputMu.Unlock()
183-
has := outputBuf.Len() > 0
184-
var t string
185-
if has {
186-
t = outputBuf.String()
187-
}
188-
return has, t
189-
}()
204+
text, hasOutput := snapshotOutputBufIfNonEmpty()
190205
if nativeWindow != nil && hasOutput {
191206
renderText(text)
192207
}

examples/location/main.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ func printLocation(vm *jni.VM, provider string, locObj *jni.Object, output *byte
142142
loc.Provider, loc.Latitude, loc.Longitude)
143143
}
144144

145+
// deliverFirstLocation stores the first received location and signals
146+
// completion. Subsequent calls are no-ops (the channel is already closed).
147+
func deliverFirstLocation(
148+
mu *sync.Mutex,
149+
result **location.ExtractedLocation,
150+
done chan struct{},
151+
loc *location.ExtractedLocation,
152+
) {
153+
mu.Lock()
154+
defer mu.Unlock()
155+
if *result == nil {
156+
*result = loc
157+
close(done)
158+
}
159+
}
160+
145161
// requestFreshLocation uses requestLocationUpdates with a JNI proxy
146162
// LocationListener to obtain a fresh GPS fix. It creates a HandlerThread
147163
// with its own Looper so callbacks can be delivered while the main thread
@@ -230,14 +246,7 @@ func requestFreshLocation(vm *jni.VM, mgr *location.Manager) (*location.Extracte
230246

231247
loc, err := location.ExtractLocation(env, locObj)
232248
if err == nil && loc != nil {
233-
func() {
234-
mu.Lock()
235-
defer mu.Unlock()
236-
if result == nil {
237-
result = loc
238-
close(done)
239-
}
240-
}()
249+
deliverFirstLocation(&mu, &result, done, loc)
241250
}
242251
}
243252
return nil, nil

proxy.go

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,38 @@ var (
2323
proxyNextID atomic.Int64
2424
)
2525

26+
// storeProxyHandler adds a handler to the global registry under the given ID.
27+
func storeProxyHandler(id int64, h ProxyHandler) {
28+
proxyMu.Lock()
29+
defer proxyMu.Unlock()
30+
proxyHandlers[id] = h
31+
}
32+
33+
// storeProxyHandlerFull adds a full handler to the global registry under the given ID.
34+
func storeProxyHandlerFull(id int64, h ProxyHandlerFull) {
35+
proxyMu.Lock()
36+
defer proxyMu.Unlock()
37+
proxyFullHandlers[id] = h
38+
}
39+
40+
// loadProxyClassLoader returns the current fallback ClassLoader reference.
41+
func loadProxyClassLoader() capi.Object {
42+
proxyMu.Lock()
43+
defer proxyMu.Unlock()
44+
return proxyClassLoader
45+
}
46+
2647
// registerProxy stores a handler and returns a unique ID.
2748
func registerProxy(h ProxyHandler) int64 {
2849
id := proxyNextID.Add(1)
29-
func() {
30-
proxyMu.Lock()
31-
defer proxyMu.Unlock()
32-
proxyHandlers[id] = h
33-
}()
50+
storeProxyHandler(id, h)
3451
return id
3552
}
3653

3754
// registerProxyFull stores a full handler and returns a unique ID.
3855
func registerProxyFull(h ProxyHandlerFull) int64 {
3956
id := proxyNextID.Add(1)
40-
func() {
41-
proxyMu.Lock()
42-
defer proxyMu.Unlock()
43-
proxyFullHandlers[id] = h
44-
}()
57+
storeProxyHandlerFull(id, h)
4558
return id
4659
}
4760

@@ -162,11 +175,7 @@ func findClassWithFallback(
162175
}
163176
capi.ExceptionClear(env)
164177

165-
cl := func() capi.Object {
166-
proxyMu.Lock()
167-
defer proxyMu.Unlock()
168-
return proxyClassLoader
169-
}()
178+
cl := loadProxyClassLoader()
170179
if cl == 0 {
171180
return 0
172181
}

0 commit comments

Comments
 (0)