@@ -54,8 +54,66 @@ void multithread_test() {
5454 __builtin_trap ();
5555}
5656
57+ void multithread_push_all_test () {
58+ constexpr static size_t NUM_THREADS = 4 ;
59+ constexpr static size_t BATCH_SIZE = 10 ;
60+ constexpr static size_t NUM_BATCHES = 20 ;
61+ struct State {
62+ MPMCStack<size_t > stack;
63+ cpp::Atomic<size_t > counter = 0 ;
64+ cpp::Atomic<bool > flags[NUM_THREADS * BATCH_SIZE * NUM_BATCHES];
65+ } state;
66+ pthread_t threads[NUM_THREADS];
67+
68+ for (size_t i = 0 ; i < NUM_THREADS; ++i) {
69+ LIBC_NAMESPACE::pthread_create (
70+ &threads[i], nullptr ,
71+ [](void *arg) -> void * {
72+ State *state = static_cast <State *>(arg);
73+ size_t values[BATCH_SIZE];
74+
75+ for (size_t batch = 0 ; batch < NUM_BATCHES; ++batch) {
76+ // Prepare batch of values
77+ for (size_t j = 0 ; j < BATCH_SIZE; ++j) {
78+ size_t current = state->counter .fetch_add (1 );
79+ values[j] = current;
80+ }
81+
82+ // Push all values in batch
83+ if (!state->stack .push_all (values, BATCH_SIZE))
84+ __builtin_trap ();
85+ }
86+
87+ // Pop and mark all values
88+ while (auto res = state->stack .pop ()) {
89+ size_t value = res.value ();
90+ if (value < NUM_THREADS * BATCH_SIZE * NUM_BATCHES)
91+ state->flags [value].store (true );
92+ }
93+ return nullptr ;
94+ },
95+ &state);
96+ }
97+
98+ for (pthread_t thread : threads)
99+ LIBC_NAMESPACE::pthread_join (thread, nullptr );
100+
101+ // Pop any remaining values
102+ while (cpp::optional<size_t > res = state.stack .pop ()) {
103+ size_t value = res.value ();
104+ if (value < NUM_THREADS * BATCH_SIZE * NUM_BATCHES)
105+ state.flags [value].store (true );
106+ }
107+
108+ // Verify all values were processed
109+ for (size_t i = 0 ; i < NUM_THREADS * BATCH_SIZE * NUM_BATCHES; ++i)
110+ if (!state.flags [i].load ())
111+ __builtin_trap ();
112+ }
113+
57114TEST_MAIN () {
58115 smoke_test ();
59116 multithread_test ();
117+ multithread_push_all_test ();
60118 return 0 ;
61119}
0 commit comments