1 /*
2  *  Copyright (c) 2024, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "test_platform.h"
30 #include "test_util.h"
31 
32 #include <openthread/config.h>
33 
34 #include "instance/instance.hpp"
35 
36 namespace ot {
37 
38 #define Log(aMessage) fprintf(stderr, aMessage "\n\r")
39 
40 static Instance *sInstance                = nullptr;
41 static bool      sTask1Handled            = false;
42 static bool      sTask2Handled            = false;
43 static bool      sTask3Handled            = false;
44 static bool      sSignalPendingCalled     = false;
45 static bool      sShouldTask3RepostItself = false;
46 
otTaskletsSignalPending(otInstance * aInstance)47 extern "C" void otTaskletsSignalPending(otInstance *aInstance)
48 {
49     Log("   otTaskletsSignalPending()");
50 
51     if (sInstance != nullptr)
52     {
53         VerifyOrQuit(aInstance == sInstance);
54     }
55 
56     sSignalPendingCalled = true;
57 }
58 
ResetTestFlags(void)59 void ResetTestFlags(void)
60 {
61     sTask1Handled        = false;
62     sTask2Handled        = false;
63     sTask3Handled        = false;
64     sSignalPendingCalled = false;
65 }
66 
CheckTaskeltFromHandler(Tasklet & aTasklet)67 void CheckTaskeltFromHandler(Tasklet &aTasklet)
68 {
69     VerifyOrQuit(&aTasklet.GetInstance() == sInstance);
70     VerifyOrQuit(!aTasklet.IsPosted());
71 }
72 
HandleTask1(Tasklet & aTasklet)73 void HandleTask1(Tasklet &aTasklet)
74 {
75     Log("   HandleTask1()");
76     CheckTaskeltFromHandler(aTasklet);
77     VerifyOrQuit(!sTask1Handled);
78     sTask1Handled = true;
79 }
80 
HandleTask2(Tasklet & aTasklet)81 void HandleTask2(Tasklet &aTasklet)
82 {
83     Log("   HandleTask2()");
84     CheckTaskeltFromHandler(aTasklet);
85     VerifyOrQuit(!sTask2Handled);
86     sTask2Handled = true;
87 }
88 
HandleTask3(Tasklet & aTasklet)89 void HandleTask3(Tasklet &aTasklet)
90 {
91     Log("   HandleTask3()");
92     CheckTaskeltFromHandler(aTasklet);
93     VerifyOrQuit(!sTask3Handled);
94     sTask3Handled = true;
95 
96     if (sShouldTask3RepostItself)
97     {
98         aTasklet.Post();
99     }
100 }
101 
TestTasklet(void)102 void TestTasklet(void)
103 {
104     Log("TestTasklet");
105 
106     sInstance = static_cast<Instance *>(testInitInstance());
107     VerifyOrQuit(sInstance != nullptr);
108 
109     sInstance->Get<Tasklet::Scheduler>().ProcessQueuedTasklets();
110 
111     {
112         Tasklet::Scheduler &scheduler = sInstance->Get<Tasklet::Scheduler>();
113         Tasklet             task1(*sInstance, HandleTask1);
114         Tasklet             task2(*sInstance, HandleTask2);
115         Tasklet             task3(*sInstance, HandleTask3);
116 
117         VerifyOrQuit(!task1.IsPosted());
118         VerifyOrQuit(!task2.IsPosted());
119         VerifyOrQuit(!task3.IsPosted());
120         VerifyOrQuit(!scheduler.AreTaskletsPending());
121 
122         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123         Log("Posting a single task");
124 
125         ResetTestFlags();
126 
127         task1.Post();
128         VerifyOrQuit(task1.IsPosted());
129         VerifyOrQuit(!task2.IsPosted());
130         VerifyOrQuit(!task3.IsPosted());
131 
132         VerifyOrQuit(sSignalPendingCalled);
133         VerifyOrQuit(scheduler.AreTaskletsPending());
134 
135         scheduler.ProcessQueuedTasklets();
136 
137         VerifyOrQuit(sTask1Handled);
138         VerifyOrQuit(!sTask2Handled);
139         VerifyOrQuit(!sTask3Handled);
140 
141         VerifyOrQuit(!scheduler.AreTaskletsPending());
142 
143         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
144         Log("Posting multiple tasks");
145 
146         ResetTestFlags();
147 
148         task3.Post();
149 
150         VerifyOrQuit(sSignalPendingCalled);
151         sSignalPendingCalled = false;
152 
153         VerifyOrQuit(scheduler.AreTaskletsPending());
154 
155         task2.Post();
156         task1.Post();
157 
158         VerifyOrQuit(!sSignalPendingCalled);
159 
160         VerifyOrQuit(task1.IsPosted());
161         VerifyOrQuit(task2.IsPosted());
162         VerifyOrQuit(task3.IsPosted());
163 
164         scheduler.ProcessQueuedTasklets();
165 
166         VerifyOrQuit(sTask1Handled);
167         VerifyOrQuit(sTask2Handled);
168         VerifyOrQuit(sTask3Handled);
169 
170         VerifyOrQuit(!scheduler.AreTaskletsPending());
171         VerifyOrQuit(!sSignalPendingCalled);
172 
173         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
174         Log("Posting the same task multiple times");
175 
176         ResetTestFlags();
177 
178         task2.Post();
179 
180         VerifyOrQuit(sSignalPendingCalled);
181         sSignalPendingCalled = false;
182 
183         VerifyOrQuit(scheduler.AreTaskletsPending());
184 
185         task2.Post();
186 
187         VerifyOrQuit(!task1.IsPosted());
188         VerifyOrQuit(task2.IsPosted());
189         VerifyOrQuit(!task3.IsPosted());
190 
191         task1.Post();
192         task2.Post();
193         task1.Post();
194 
195         VerifyOrQuit(!sSignalPendingCalled);
196 
197         VerifyOrQuit(task1.IsPosted());
198         VerifyOrQuit(task2.IsPosted());
199         VerifyOrQuit(!task3.IsPosted());
200 
201         scheduler.ProcessQueuedTasklets();
202 
203         VerifyOrQuit(sTask1Handled);
204         VerifyOrQuit(sTask2Handled);
205         VerifyOrQuit(!sTask3Handled);
206 
207         VerifyOrQuit(!scheduler.AreTaskletsPending());
208         VerifyOrQuit(!sSignalPendingCalled);
209 
210         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211         Log("Task posting itself from its handler");
212 
213         ResetTestFlags();
214         sShouldTask3RepostItself = true;
215 
216         task3.Post();
217 
218         VerifyOrQuit(sSignalPendingCalled);
219         sSignalPendingCalled = false;
220         VerifyOrQuit(scheduler.AreTaskletsPending());
221 
222         task2.Post();
223         VerifyOrQuit(!sSignalPendingCalled);
224         VerifyOrQuit(scheduler.AreTaskletsPending());
225 
226         VerifyOrQuit(!task1.IsPosted());
227         VerifyOrQuit(task2.IsPosted());
228         VerifyOrQuit(task3.IsPosted());
229 
230         scheduler.ProcessQueuedTasklets();
231 
232         VerifyOrQuit(!sTask1Handled);
233         VerifyOrQuit(sTask2Handled);
234         VerifyOrQuit(sTask3Handled);
235 
236         VerifyOrQuit(scheduler.AreTaskletsPending());
237         VerifyOrQuit(sSignalPendingCalled);
238 
239         ResetTestFlags();
240 
241         sShouldTask3RepostItself = false;
242 
243         scheduler.ProcessQueuedTasklets();
244         VerifyOrQuit(!sTask1Handled);
245         VerifyOrQuit(!sTask2Handled);
246         VerifyOrQuit(sTask3Handled);
247 
248         VerifyOrQuit(!sSignalPendingCalled);
249         VerifyOrQuit(!scheduler.AreTaskletsPending());
250 
251         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
252         Log("Un-posting a single posted task");
253 
254         ResetTestFlags();
255 
256         task1.Post();
257 
258         VerifyOrQuit(sSignalPendingCalled);
259         sSignalPendingCalled = false;
260         VerifyOrQuit(scheduler.AreTaskletsPending());
261 
262         VerifyOrQuit(task1.IsPosted());
263 
264         task1.Unpost();
265 
266         VerifyOrQuit(!sSignalPendingCalled);
267         VerifyOrQuit(!scheduler.AreTaskletsPending());
268 
269         VerifyOrQuit(!task1.IsPosted());
270 
271         scheduler.ProcessQueuedTasklets();
272 
273         VerifyOrQuit(!sTask1Handled);
274         VerifyOrQuit(!sTask2Handled);
275         VerifyOrQuit(!sTask3Handled);
276 
277         VerifyOrQuit(!sSignalPendingCalled);
278         VerifyOrQuit(!scheduler.AreTaskletsPending());
279 
280         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
281         Log("Post multiple tasks and then un-post the first one");
282 
283         ResetTestFlags();
284 
285         task1.Post();
286         task2.Post();
287         task3.Post();
288 
289         VerifyOrQuit(sSignalPendingCalled);
290         sSignalPendingCalled = false;
291         VerifyOrQuit(scheduler.AreTaskletsPending());
292 
293         VerifyOrQuit(task1.IsPosted());
294         VerifyOrQuit(task2.IsPosted());
295         VerifyOrQuit(task3.IsPosted());
296 
297         task1.Unpost();
298 
299         VerifyOrQuit(!task1.IsPosted());
300         VerifyOrQuit(task2.IsPosted());
301         VerifyOrQuit(task3.IsPosted());
302 
303         scheduler.ProcessQueuedTasklets();
304 
305         VerifyOrQuit(!sTask1Handled);
306         VerifyOrQuit(sTask2Handled);
307         VerifyOrQuit(sTask3Handled);
308 
309         VerifyOrQuit(!sSignalPendingCalled);
310         VerifyOrQuit(!scheduler.AreTaskletsPending());
311 
312         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
313         Log("Post multiple tasks and then un-post the middle one");
314 
315         ResetTestFlags();
316 
317         task1.Post();
318         task2.Post();
319         task3.Post();
320 
321         VerifyOrQuit(sSignalPendingCalled);
322         sSignalPendingCalled = false;
323         VerifyOrQuit(scheduler.AreTaskletsPending());
324 
325         VerifyOrQuit(task1.IsPosted());
326         VerifyOrQuit(task2.IsPosted());
327         VerifyOrQuit(task3.IsPosted());
328 
329         task2.Unpost();
330 
331         VerifyOrQuit(task1.IsPosted());
332         VerifyOrQuit(!task2.IsPosted());
333         VerifyOrQuit(task3.IsPosted());
334 
335         scheduler.ProcessQueuedTasklets();
336 
337         VerifyOrQuit(sTask1Handled);
338         VerifyOrQuit(!sTask2Handled);
339         VerifyOrQuit(sTask3Handled);
340 
341         VerifyOrQuit(!sSignalPendingCalled);
342         VerifyOrQuit(!scheduler.AreTaskletsPending());
343 
344         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
345         Log("Post multiple tasks and then un-post the last one");
346 
347         ResetTestFlags();
348 
349         task1.Post();
350         task2.Post();
351         task3.Post();
352 
353         VerifyOrQuit(sSignalPendingCalled);
354         sSignalPendingCalled = false;
355         VerifyOrQuit(scheduler.AreTaskletsPending());
356 
357         VerifyOrQuit(task1.IsPosted());
358         VerifyOrQuit(task2.IsPosted());
359         VerifyOrQuit(task3.IsPosted());
360 
361         task3.Unpost();
362 
363         VerifyOrQuit(task1.IsPosted());
364         VerifyOrQuit(task2.IsPosted());
365         VerifyOrQuit(!task3.IsPosted());
366 
367         scheduler.ProcessQueuedTasklets();
368 
369         VerifyOrQuit(sTask1Handled);
370         VerifyOrQuit(sTask2Handled);
371         VerifyOrQuit(!sTask3Handled);
372 
373         VerifyOrQuit(!sSignalPendingCalled);
374         VerifyOrQuit(!scheduler.AreTaskletsPending());
375 
376         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
377         Log("Post multiple tasks and then un-post the first and last ones");
378 
379         ResetTestFlags();
380 
381         task1.Post();
382         task2.Post();
383         task3.Post();
384 
385         VerifyOrQuit(sSignalPendingCalled);
386         sSignalPendingCalled = false;
387         VerifyOrQuit(scheduler.AreTaskletsPending());
388 
389         VerifyOrQuit(task1.IsPosted());
390         VerifyOrQuit(task2.IsPosted());
391         VerifyOrQuit(task3.IsPosted());
392 
393         task1.Unpost();
394         task3.Unpost();
395 
396         VerifyOrQuit(!task1.IsPosted());
397         VerifyOrQuit(task2.IsPosted());
398         VerifyOrQuit(!task3.IsPosted());
399 
400         scheduler.ProcessQueuedTasklets();
401 
402         VerifyOrQuit(!sTask1Handled);
403         VerifyOrQuit(sTask2Handled);
404         VerifyOrQuit(!sTask3Handled);
405 
406         VerifyOrQuit(!sSignalPendingCalled);
407         VerifyOrQuit(!scheduler.AreTaskletsPending());
408 
409         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
410         Log("Post multiple tasks and then un-post all in the same order added");
411 
412         ResetTestFlags();
413 
414         task1.Post();
415         task2.Post();
416         task3.Post();
417 
418         VerifyOrQuit(sSignalPendingCalled);
419         sSignalPendingCalled = false;
420         VerifyOrQuit(scheduler.AreTaskletsPending());
421 
422         VerifyOrQuit(task1.IsPosted());
423         VerifyOrQuit(task2.IsPosted());
424         VerifyOrQuit(task3.IsPosted());
425 
426         task1.Unpost();
427         task2.Unpost();
428         task3.Unpost();
429 
430         VerifyOrQuit(!task1.IsPosted());
431         VerifyOrQuit(!task2.IsPosted());
432         VerifyOrQuit(!task3.IsPosted());
433 
434         VerifyOrQuit(!scheduler.AreTaskletsPending());
435 
436         scheduler.ProcessQueuedTasklets();
437 
438         VerifyOrQuit(!sTask1Handled);
439         VerifyOrQuit(!sTask2Handled);
440         VerifyOrQuit(!sTask3Handled);
441 
442         VerifyOrQuit(!sSignalPendingCalled);
443         VerifyOrQuit(!scheduler.AreTaskletsPending());
444 
445         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
446         Log("Post multiple tasks and then un-post all in the reverse order added");
447 
448         ResetTestFlags();
449 
450         task1.Post();
451         task2.Post();
452         task3.Post();
453 
454         VerifyOrQuit(sSignalPendingCalled);
455         sSignalPendingCalled = false;
456         VerifyOrQuit(scheduler.AreTaskletsPending());
457 
458         VerifyOrQuit(task1.IsPosted());
459         VerifyOrQuit(task2.IsPosted());
460         VerifyOrQuit(task3.IsPosted());
461 
462         task3.Unpost();
463         task2.Unpost();
464         task1.Unpost();
465 
466         VerifyOrQuit(!task1.IsPosted());
467         VerifyOrQuit(!task2.IsPosted());
468         VerifyOrQuit(!task3.IsPosted());
469 
470         VerifyOrQuit(!scheduler.AreTaskletsPending());
471 
472         scheduler.ProcessQueuedTasklets();
473 
474         VerifyOrQuit(!sTask1Handled);
475         VerifyOrQuit(!sTask2Handled);
476         VerifyOrQuit(!sTask3Handled);
477 
478         VerifyOrQuit(!sSignalPendingCalled);
479         VerifyOrQuit(!scheduler.AreTaskletsPending());
480 
481         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
482         Log("Post multiple tasks and then un-post all in different order (middle first)");
483 
484         ResetTestFlags();
485 
486         task1.Post();
487         task2.Post();
488         task3.Post();
489 
490         VerifyOrQuit(sSignalPendingCalled);
491         sSignalPendingCalled = false;
492         VerifyOrQuit(scheduler.AreTaskletsPending());
493 
494         VerifyOrQuit(task1.IsPosted());
495         VerifyOrQuit(task2.IsPosted());
496         VerifyOrQuit(task3.IsPosted());
497 
498         task2.Unpost();
499         task3.Unpost();
500         task1.Unpost();
501 
502         VerifyOrQuit(!task1.IsPosted());
503         VerifyOrQuit(!task2.IsPosted());
504         VerifyOrQuit(!task3.IsPosted());
505 
506         VerifyOrQuit(!scheduler.AreTaskletsPending());
507 
508         scheduler.ProcessQueuedTasklets();
509 
510         VerifyOrQuit(!sTask1Handled);
511         VerifyOrQuit(!sTask2Handled);
512         VerifyOrQuit(!sTask3Handled);
513 
514         VerifyOrQuit(!sSignalPendingCalled);
515         VerifyOrQuit(!scheduler.AreTaskletsPending());
516 
517         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
518         Log("Un-posting tasks not yet posted");
519 
520         ResetTestFlags();
521 
522         task1.Unpost();
523 
524         VerifyOrQuit(!task1.IsPosted());
525 
526         VerifyOrQuit(!sSignalPendingCalled);
527         VerifyOrQuit(!scheduler.AreTaskletsPending());
528 
529         task2.Post();
530 
531         VerifyOrQuit(sSignalPendingCalled);
532         sSignalPendingCalled = false;
533         VerifyOrQuit(scheduler.AreTaskletsPending());
534 
535         task1.Unpost();
536         task3.Unpost();
537 
538         VerifyOrQuit(!task1.IsPosted());
539         VerifyOrQuit(task2.IsPosted());
540         VerifyOrQuit(!task3.IsPosted());
541 
542         VerifyOrQuit(scheduler.AreTaskletsPending());
543 
544         task3.Post();
545 
546         VerifyOrQuit(!task1.IsPosted());
547         VerifyOrQuit(task2.IsPosted());
548         VerifyOrQuit(task3.IsPosted());
549 
550         VerifyOrQuit(!sSignalPendingCalled);
551         VerifyOrQuit(scheduler.AreTaskletsPending());
552 
553         scheduler.ProcessQueuedTasklets();
554 
555         VerifyOrQuit(!sTask1Handled);
556         VerifyOrQuit(sTask2Handled);
557         VerifyOrQuit(sTask3Handled);
558 
559         VerifyOrQuit(!sSignalPendingCalled);
560         VerifyOrQuit(!scheduler.AreTaskletsPending());
561     }
562 }
563 
564 } // namespace ot
565 
main(void)566 int main(void)
567 {
568     ot::TestTasklet();
569     printf("All tests passed\n");
570     return 0;
571 }
572