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);
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+ // Now sleep 800 msec and unlock the mutex
72+ wait_latch (ctx->sequence_latch , 6 );
5973 ipc::Thread::sleep (800 );
60- ctx->log (mutex.unlock (), " SYNC2" , STATUS_OK);
74+ ctx->log (mutex.unlock (), " SYNC2.unlock" , STATUS_OK);
75+ atomic_add (&ctx->sequence_latch , 1 ); // 6 -> 8
76+
77+ // Close the mutex
78+ wait_latch (ctx->sequence_latch , 9 );
79+ ctx->log (mutex.close (), " close1" , STATUS_OK);
80+ atomic_add (&ctx->sequence_latch , 1 ); // 9 -> 10
6181
6282 return STATUS_OK;
6383 }
@@ -67,24 +87,43 @@ 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+ ctx->log (mutex.lock (500 ), " SYNC2.lock" , STATUS_OK);
106+ atomic_add (&ctx->sequence_latch , 1 ); // 6 -> 8
107+
108+ // Sleep 200 milliseconds and unlock the mutex
109+ wait_latch (ctx->sequence_latch , 8 );
82110 ipc::Thread::sleep (200 );
83- ctx->log (mutex.unlock (), " SYNC3" , STATUS_OK);
111+ ctx->log (mutex.unlock (), " SYNC3.unlock" , STATUS_OK);
112+
113+ // Close the mutex
114+ wait_latch (ctx->sequence_latch , 10 );
115+ ctx->log (mutex.close (), " close2" , STATUS_OK);
116+ atomic_add (&ctx->sequence_latch , 1 ); // 10 -> 11
84117
85118 return STATUS_OK;
86119 }
87120
121+ static void wait_latch (uatomic_t & latch, uatomic_t value)
122+ {
123+ while (atomic_load (&latch) != value)
124+ ipc::Thread::yield ();
125+ }
126+
88127 void test_simple ()
89128 {
90129 ipc::SharedMutex mutex;
@@ -122,6 +161,7 @@ UTEST_BEGIN("runtime.ipc", shmutex)
122161 {
123162 ipc::SharedMutex mutex;
124163 context_t ctx;
164+ atomic_store (&ctx.sequence_latch , uatomic_t (0 ));
125165
126166 printf (" Testing simple multi-threaded mutex locks\n " );
127167
@@ -134,24 +174,31 @@ UTEST_BEGIN("runtime.ipc", shmutex)
134174 ctx.log (STATUS_OK, " start" , STATUS_OK);
135175 t1.start ();
136176 t2.start ();
177+ wait_latch (ctx.sequence_latch , 2 );
178+ atomic_add (&ctx.sequence_latch , 1 ); // 2 -> 3
137179
180+ // Sleep 200 ms and unlock the mutex
138181 ctx.log (STATUS_OK, " sleep" , STATUS_OK);
139182 ipc::Thread::sleep (200 );
140-
141183 ctx.log (STATUS_OK, " unlock" , STATUS_OK);
142184 UTEST_ASSERT (mutex.unlock () == STATUS_OK);
185+ atomic_add (&ctx.sequence_latch , 1 ); // 3 -> 6
143186
144- ipc::Thread::sleep (2000 );
145- ctx.log (mutex.lock (), " SYNC3" , STATUS_OK);
187+ // Lock the mutex, unlock it and return result
188+ wait_latch (ctx.sequence_latch , 8 );
189+ ctx.log (mutex.lock (), " SYNC3.lock" , STATUS_OK);
146190 ctx.log (mutex.unlock (), " unlock" , STATUS_OK);
147191
148192 ctx.log (mutex.close (), " close" , STATUS_OK);
193+ atomic_add (&ctx.sequence_latch , 1 ); // 8 -> 9
149194
195+ // Do final comparison
196+ wait_latch (ctx.sequence_latch , 11 );
150197 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;" ;
198+ " open=true;lock=true;start=true;open1 =true;open2=true;sleep =true;unlock =true;lock2 =true;"
199+ " SYNC1.unlock =true;SYNC1.lock =true;trylock2=true;timedlock2=true;"
200+ " SYNC2.unlock =true;SYNC2.lock =true;"
201+ " SYNC3.unlock =true;SYNC3.lock =true;unlock=true;close=true;close1=true;close2 =true;" ;
155202
156203 printf (" Result content: %s\n " , ctx.data .get_ascii ());
157204 printf (" Expected content: %s\n " , expected);
0 commit comments