Skip to content

Commit 80528a5

Browse files
committed
Original PR had drifted too far
1 parent cb8d502 commit 80528a5

File tree

4 files changed

+129
-37
lines changed

4 files changed

+129
-37
lines changed

system/lib/pthread/emscripten_thread_state.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ emscripten_is_main_browser_thread:
5353
global.get is_main_thread
5454
end_function
5555

56-
# Semantically the same as testing "!ENVIRONMENT_IS_WEB" in JS
56+
# Semantically the same as testing "!ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_AUDIO_WORKLET" in JS
5757
.globl _emscripten_thread_supports_atomics_wait
5858
_emscripten_thread_supports_atomics_wait:
5959
.functype _emscripten_thread_supports_atomics_wait () -> (i32)

system/lib/wasm_worker/library_wasm_worker.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,17 @@ void emscripten_lock_waitinf_acquire(emscripten_lock_t *lock) {
105105
}
106106

107107
bool emscripten_lock_busyspin_wait_acquire(emscripten_lock_t *lock, double maxWaitMilliseconds) {
108+
// TODO: we changed the performance_now calls to get_now, which can be applied
109+
// to the remaining code (since all calls defer to the best internal option).
108110
emscripten_lock_t val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
109111
if (!val) return true;
110112

111-
double t = emscripten_performance_now();
113+
double t = emscripten_get_now();
112114
double waitEnd = t + maxWaitMilliseconds;
113115
while (t < waitEnd) {
114116
val = emscripten_atomic_cas_u32((void*)lock, 0, 1);
115117
if (!val) return true;
116-
t = emscripten_performance_now();
118+
t = emscripten_get_now();
117119
}
118120
return false;
119121
}

test/test_browser.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5516,12 +5516,11 @@ def test_audio_worklet_params_mixing(self, args):
55165516
shutil.copy(test_file('webaudio/audio_files/emscripten-bass.mp3'), 'audio_files/')
55175517
self.btest_exit('webaudio/audioworklet_params_mixing.c', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-DTEST_AND_EXIT'] + args)
55185518

5519-
# Tests AudioWorklet with emscripten_futex_wake().
5519+
# Tests AudioWorklet with emscripten_lock_busyspin_wait_acquire() and friends.
55205520
@requires_sound_hardware
55215521
@also_with_minimal_runtime
5522-
@disabled('https://github.com/emscripten-core/emscripten/issues/22962')
55235522
def test_audio_worklet_emscripten_futex_wake(self):
5524-
self.btest('webaudio/audioworklet_emscripten_futex_wake.cpp', expected='0', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread', '-sPTHREAD_POOL_SIZE=2'])
5523+
self.btest_exit('webaudio/audioworklet_emscripten_futex_wake.cpp', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-pthread', '-sPTHREAD_POOL_SIZE=2'])
55255524

55265525
def test_error_reporting(self):
55275526
# Test catching/reporting Error objects
Lines changed: 122 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,107 @@
1-
#include <emscripten/webaudio.h>
21
#include <emscripten/threading.h>
2+
#include <emscripten/wasm_worker.h>
3+
#include <emscripten/webaudio.h>
34
#include <stdio.h>
45
#include <stdlib.h>
56
#include <assert.h>
67

7-
// Tests that
8-
// - _emscripten_thread_supports_atomics_wait() returns true in a Wasm Audio Worklet.
9-
// - emscripten_futex_wake() does not crash in a Wasm Audio Worklet.
10-
// - emscripten_futex_wait() does not crash in a Wasm Audio Worklet.
11-
// - emscripten_get_now() does not crash in a Wasm Audio Worklet.
12-
13-
int futexLocation = 0;
14-
int testSuccess = 0;
8+
// Tests that these audio worklet compatible functions work, details in comments below:
9+
//
10+
// - _emscripten_thread_supports_atomics_wait()
11+
// - emscripten_lock_init()
12+
// - emscripten_lock_try_acquire()
13+
// - emscripten_lock_busyspin_wait_acquire()
14+
// - emscripten_lock_busyspin_waitinf_acquire()
15+
// - emscripten_lock_release()
16+
// - emscripten_get_now()
1517

1618
// Internal, found in 'system/lib/pthread/threading_internal.h'
17-
extern "C" int _emscripten_thread_supports_atomics_wait();
19+
extern "C" int _emscripten_thread_supports_atomics_wait(void);
1820

19-
bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) {
20-
int supportsAtomicWait = _emscripten_thread_supports_atomics_wait();
21-
printf("supportsAtomicWait: %d\n", supportsAtomicWait);
22-
assert(!supportsAtomicWait);
23-
emscripten_futex_wake(&futexLocation, 1);
24-
printf("%f\n", emscripten_get_now());
21+
typedef enum {
22+
// No wait support in audio worklets
23+
TEST_HAS_WAIT,
24+
// Acquired in main, fail in process
25+
TEST_TRY_ACQUIRE,
26+
// Keep acquired so time-out
27+
TEST_WAIT_ACQUIRE_FAIL,
28+
// Release in main, succeed in process
29+
TEST_WAIT_ACQUIRE,
30+
// Release in process after above
31+
TEST_RELEASE,
32+
// Released in process above, spin in main
33+
TEST_WAIT_INFINTE_1,
34+
// Release in process to stop spinning in main
35+
TEST_WAIT_INFINTE_2,
36+
// Call emscripten_get_now() in process
37+
TEST_GET_NOW,
38+
// Test finished
39+
TEST_DONE
40+
} Test;
2541

26-
emscripten_futex_wait(&futexLocation, 1, /*maxWaitMs=*/2);
27-
testSuccess = 1;
42+
// Lock used in all the tests
43+
emscripten_lock_t testLock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER;
44+
// Which test is running (sometimes in the worklet, sometimes in the main thread)
45+
_Atomic Test whichTest = TEST_HAS_WAIT;
46+
// Time at which the test starts taken in main()
47+
double startTime = 0;
2848

29-
return false;
49+
bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) {
50+
int result = 0;
51+
switch (whichTest) {
52+
case TEST_HAS_WAIT:
53+
// Should not have wait support here
54+
result = _emscripten_thread_supports_atomics_wait();
55+
printf("TEST_HAS_WAIT: %d (expect: 0)\n", result);
56+
assert(!result);
57+
whichTest = TEST_TRY_ACQUIRE;
58+
break;
59+
case TEST_TRY_ACQUIRE:
60+
// Was locked after init, should fail to acquire
61+
result = emscripten_lock_try_acquire(&testLock);
62+
printf("TEST_TRY_ACQUIRE: %d (expect: 0)\n", result);
63+
assert(!result);
64+
whichTest = TEST_WAIT_ACQUIRE_FAIL;
65+
break;
66+
case TEST_WAIT_ACQUIRE_FAIL:
67+
// Still locked so we fail to acquire
68+
result = emscripten_lock_busyspin_wait_acquire(&testLock, 100);
69+
printf("TEST_WAIT_ACQUIRE_FAIL: %d (expect: 0)\n", result);
70+
assert(!result);
71+
whichTest = TEST_WAIT_ACQUIRE;
72+
case TEST_WAIT_ACQUIRE:
73+
// Will get unlocked in main thread, so should quickly acquire
74+
result = emscripten_lock_busyspin_wait_acquire(&testLock, 100);
75+
printf("TEST_WAIT_ACQUIRE: %d (expect: 1)\n", result);
76+
assert(result);
77+
whichTest = TEST_RELEASE;
78+
break;
79+
case TEST_RELEASE:
80+
// Unlock, check the result
81+
emscripten_lock_release(&testLock);
82+
result = emscripten_lock_try_acquire(&testLock);
83+
printf("TEST_RELEASE: %d (expect: 1)\n", result);
84+
assert(result);
85+
whichTest = TEST_WAIT_INFINTE_1;
86+
break;
87+
case TEST_WAIT_INFINTE_1:
88+
// Still locked when we enter here but move on in the main thread
89+
break;
90+
case TEST_WAIT_INFINTE_2:
91+
emscripten_lock_release(&testLock);
92+
whichTest = TEST_GET_NOW;
93+
break;
94+
case TEST_GET_NOW:
95+
result = (int) (emscripten_get_now() - startTime);
96+
printf("TEST_GET_NOW: %d (expect: > 0)\n", result);
97+
assert(result > 0);
98+
whichTest = TEST_DONE;
99+
case TEST_DONE:
100+
return false;
101+
default:
102+
break;
103+
}
104+
return true;
30105
}
31106

32107
EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), {
@@ -40,34 +115,50 @@ EM_JS(void, InitHtmlUi, (EMSCRIPTEN_WEBAUDIO_T audioContext), {
40115
};
41116
});
42117

43-
bool PollTestSuccess(double, void *) {
44-
if (testSuccess) {
45-
printf("Test success!\n");
46-
#ifdef REPORT_RESULT
47-
REPORT_RESULT(0);
48-
#endif
118+
bool MainLoop(double time, void* data) {
119+
switch (whichTest) {
120+
case TEST_WAIT_ACQUIRE:
121+
// Release here to acquire in process
122+
emscripten_lock_release(&testLock);
123+
break;
124+
case TEST_WAIT_INFINTE_1:
125+
// Spin here until released in process (but don't change test until we know this case ran)
126+
whichTest = TEST_WAIT_INFINTE_2;
127+
emscripten_lock_busyspin_waitinf_acquire(&testLock);
128+
printf("TEST_WAIT_INFINTE (from main)\n");
129+
break;
130+
case TEST_DONE:
49131
return false;
132+
default:
133+
break;
50134
}
51135
return true;
52136
}
53137

54138
void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) {
55139
int outputChannelCounts[1] = { 1 };
56140
EmscriptenAudioWorkletNodeCreateOptions options = { .numberOfInputs = 0, .numberOfOutputs = 1, .outputChannelCounts = outputChannelCounts };
57-
EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "noise-generator", &options, &ProcessAudio, 0);
141+
EMSCRIPTEN_AUDIO_WORKLET_NODE_T wasmAudioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "noise-generator", &options, &ProcessAudio, NULL);
58142
emscripten_audio_node_connect(wasmAudioWorklet, audioContext, 0, 0);
59143
InitHtmlUi(audioContext);
60144
}
61145

62146
void WebAudioWorkletThreadInitialized(EMSCRIPTEN_WEBAUDIO_T audioContext, bool success, void *userData) {
63147
WebAudioWorkletProcessorCreateOptions opts = { .name = "noise-generator" };
64-
emscripten_create_wasm_audio_worklet_processor_async(audioContext, &opts, AudioWorkletProcessorCreated, 0);
148+
emscripten_create_wasm_audio_worklet_processor_async(audioContext, &opts, AudioWorkletProcessorCreated, NULL);
65149
}
66150

67-
uint8_t wasmAudioWorkletStack[4096];
151+
uint8_t wasmAudioWorkletStack[2048];
68152

69153
int main() {
70-
emscripten_set_timeout_loop(PollTestSuccess, 10, 0);
71-
EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context(0);
72-
emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, 0);
154+
// Main thread init and acquire (work passes to the processor)
155+
emscripten_lock_init(&testLock);
156+
int hasLock = emscripten_lock_busyspin_wait_acquire(&testLock, 0);
157+
assert(hasLock);
158+
159+
startTime = emscripten_get_now();
160+
161+
emscripten_set_timeout_loop(MainLoop, 10, NULL);
162+
EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context(NULL);
163+
emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, NULL);
73164
}

0 commit comments

Comments
 (0)