2020 */
2121
2222#include < lsp-plug.in/test-fw/utest.h>
23+ #include < lsp-plug.in/common/atomic.h>
2324#include < lsp-plug.in/ipc/Thread.h>
2425#include < lsp-plug.in/ipc/Mutex.h>
2526#include < lsp-plug.in/ipc/SharedMutex.h>
@@ -34,6 +35,7 @@ UTEST_BEGIN("runtime.ipc", shmutex)
3435 {
3536 ipc::Mutex lock;
3637 LSPString data;
38+ uatomic_t sequence_latch;
3739
3840 void log (status_t code, const char *event, status_t expected)
3941 {
@@ -42,7 +44,10 @@ UTEST_BEGIN("runtime.ipc", shmutex)
4244
4345 data.append_ascii (event);
4446 data.append (' =' );
45- data.append_ascii ((code == expected) ? " true" : " false" );
47+ if (code == expected)
48+ data.append_ascii (" true" );
49+ else
50+ data.fmt_append_ascii (" false(code=%d)" , int (code));
4651 data.append (' ;' );
4752 }
4853 } context_t ;
@@ -53,11 +58,26 @@ UTEST_BEGIN("runtime.ipc", shmutex)
5358 ipc::SharedMutex mutex;
5459 context_t *ctx = static_cast <context_t *>(arg);
5560
56- ipc::Thread::sleep ( 500 );
61+ wait_latch (ctx-> sequence_latch , 0 );
5762 ctx->log (mutex.open (" test-lsp.lock" ), " open1" , STATUS_OK);
58- ctx->log (mutex.lock (), " SYNC1" , STATUS_OK);
59- ipc::Thread::sleep (800 );
60- ctx->log (mutex.unlock (), " SYNC2" , STATUS_OK);
63+ atomic_add (&ctx->sequence_latch , 1 ); // 0 -> 1
64+
65+ // Sleep 500 ms and lock the mutex
66+ wait_latch (ctx->sequence_latch , 3 );
67+ ipc::Thread::sleep (500 );
68+ ctx->log (mutex.lock (), " SYNC1.lock" , STATUS_OK);
69+ atomic_add (&ctx->sequence_latch , 1 ); // 3 -> 6
70+
71+ // Sleep 200 ms and unlock the mutex
72+ wait_latch (ctx->sequence_latch , 7 );
73+ ipc::Thread::sleep (200 );
74+ ctx->log (mutex.unlock (), " SYNC2.unlock" , STATUS_OK);
75+ atomic_add (&ctx->sequence_latch , 1 ); // 7 -> 9
76+
77+ // Close the mutex
78+ wait_latch (ctx->sequence_latch , 10 );
79+ ctx->log (mutex.close (), " close1" , STATUS_OK);
80+ atomic_add (&ctx->sequence_latch , 1 ); // 10 -> 11
6181
6282 return STATUS_OK;
6383 }
@@ -67,24 +87,47 @@ UTEST_BEGIN("runtime.ipc", shmutex)
6787 ipc::SharedMutex mutex;
6888 context_t *ctx = static_cast <context_t *>(arg);
6989
90+ wait_latch (ctx->sequence_latch , 1 );
7091 ctx->log (mutex.open (" test-lsp.lock" ), " open2" , STATUS_OK);
71- ctx->log (mutex. lock (), " lock2 " , STATUS_OK);
92+ atomic_add (& ctx->sequence_latch , 1 ); // 1 -> 2
7293
94+ // Lock mutex immediately, sleep 500 ms and unlock it
95+ wait_latch (ctx->sequence_latch , 3 );
96+ ctx->log (mutex.lock (), " lock2" , STATUS_OK);
7397 ipc::Thread::sleep (500 );
98+ ctx->log (mutex.unlock (), " SYNC1.unlock" , STATUS_OK);
99+ atomic_add (&ctx->sequence_latch , 1 ); // 3 -> 6
74100
75- ctx->log (mutex.unlock (), " SYNC1" , STATUS_OK);
76-
77- ipc::Thread::sleep (100 );
78-
101+ // Call mutltiple times lock, succeed on last call
102+ wait_latch (ctx->sequence_latch , 6 );
79103 ctx->log (mutex.try_lock (), " trylock2" , STATUS_RETRY);
80104 ctx->log (mutex.lock (500 ), " timedlock2" , STATUS_TIMED_OUT);
81- ctx->log (mutex.lock (500 ), " SYNC2" , STATUS_OK);
105+ atomic_add (&ctx->sequence_latch , 1 ); // 6 -> 7
106+
107+ // Succeed on timed mutex lock
108+ wait_latch (ctx->sequence_latch , 7 );
109+ ctx->log (mutex.lock (800 ), " SYNC2.lock" , STATUS_OK);
110+ atomic_add (&ctx->sequence_latch , 1 ); // 7 -> 9
111+
112+ // Sleep 200 milliseconds and unlock the mutex
113+ wait_latch (ctx->sequence_latch , 9 );
82114 ipc::Thread::sleep (200 );
83- ctx->log (mutex.unlock (), " SYNC3" , STATUS_OK);
115+ ctx->log (mutex.unlock (), " SYNC3.unlock" , STATUS_OK);
116+
117+ // Close the mutex
118+ wait_latch (ctx->sequence_latch , 11 );
119+ ctx->log (mutex.close (), " close2" , STATUS_OK);
120+ atomic_add (&ctx->sequence_latch , 1 ); // 11 -> 12
84121
85122 return STATUS_OK;
86123 }
87124
125+ static void wait_latch (uatomic_t & latch, uatomic_t value)
126+ {
127+ while (atomic_load (&latch) != value)
128+ ipc::Thread::yield ();
129+ }
130+
88131 void test_simple ()
89132 {
90133 ipc::SharedMutex mutex;
@@ -122,6 +165,7 @@ UTEST_BEGIN("runtime.ipc", shmutex)
122165 {
123166 ipc::SharedMutex mutex;
124167 context_t ctx;
168+ atomic_store (&ctx.sequence_latch , uatomic_t (0 ));
125169
126170 printf (" Testing simple multi-threaded mutex locks\n " );
127171
@@ -134,24 +178,31 @@ UTEST_BEGIN("runtime.ipc", shmutex)
134178 ctx.log (STATUS_OK, " start" , STATUS_OK);
135179 t1.start ();
136180 t2.start ();
181+ wait_latch (ctx.sequence_latch , 2 );
182+ atomic_add (&ctx.sequence_latch , 1 ); // 2 -> 3
137183
184+ // Sleep 200 ms and unlock the mutex
138185 ctx.log (STATUS_OK, " sleep" , STATUS_OK);
139186 ipc::Thread::sleep (200 );
140-
141187 ctx.log (STATUS_OK, " unlock" , STATUS_OK);
142188 UTEST_ASSERT (mutex.unlock () == STATUS_OK);
189+ atomic_add (&ctx.sequence_latch , 1 ); // 3 -> 6
143190
144- ipc::Thread::sleep (2000 );
145- ctx.log (mutex.lock (), " SYNC3" , STATUS_OK);
191+ // Lock the mutex, unlock it and return result
192+ wait_latch (ctx.sequence_latch , 9 );
193+ ctx.log (mutex.lock (), " SYNC3.lock" , STATUS_OK);
146194 ctx.log (mutex.unlock (), " unlock" , STATUS_OK);
147195
148196 ctx.log (mutex.close (), " close" , STATUS_OK);
197+ atomic_add (&ctx.sequence_latch , 1 ); // 9 -> 10
149198
199+ // Do final comparison
200+ wait_latch (ctx.sequence_latch , 12 );
150201 static const char *expected =
151- " open=true;lock=true;start=true;sleep =true;open2=true;unlock =true;lock2 =true;open1 =true;"
152- " SYNC1=true;SYNC1=true;trylock2=true;timedlock2=true;"
153- " SYNC2=true;SYNC2=true;"
154- " SYNC3=true;SYNC3=true;unlock=true;close=true;" ;
202+ " open=true;lock=true;start=true;open1 =true;open2=true;sleep =true;unlock =true;lock2 =true;"
203+ " SYNC1.unlock =true;SYNC1.lock =true;trylock2=true;timedlock2=true;"
204+ " SYNC2.unlock =true;SYNC2.lock =true;"
205+ " SYNC3.unlock =true;SYNC3.lock =true;unlock=true;close=true;close1=true;close2 =true;" ;
155206
156207 printf (" Result content: %s\n " , ctx.data .get_ascii ());
157208 printf (" Expected content: %s\n " , expected);
0 commit comments