source: rtems-libbsd/testsuite/mutex01/test_main.c @ eae664e

55-freebsd-126-freebsd-12
Last change on this file since eae664e was eae664e, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 12, 2018 at 1:38:46 PM

mutex: Use panic() after ISR lock release

Using panic() with interrupts disabled could lead to an additional error
(INTERNAL_ERROR_BAD_THREAD_DISPATCH_ENVIRONMENT) due to a potentially
blocking output.

  • Property mode set to 100644
File size: 12.9 KB
Line 
1/*
2 * Copyright (c) 2014, 2018 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <machine/rtems-bsd-kernel-space.h>
33
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/systm.h>
37#include <sys/lock.h>
38#include <sys/mutex.h>
39
40#include <assert.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44
45#include <rtems/libcsupport.h>
46#include <rtems.h>
47
48#define TEST_NAME "LIBBSD MUTEX 1"
49
50#define PRIO_MASTER 3
51
52#define EVENT_LOCK RTEMS_EVENT_0
53
54#define EVENT_TRY_LOCK RTEMS_EVENT_1
55
56#define EVENT_UNLOCK RTEMS_EVENT_2
57
58#define EVENT_SLEEP RTEMS_EVENT_3
59
60#define WORKER_COUNT 2
61
62typedef struct {
63        struct mtx mtx;
64        struct mtx mtx2;
65        int rv;
66        int timo;
67        rtems_id worker_task[WORKER_COUNT];
68        bool done[WORKER_COUNT];
69        rtems_id panic_task;
70} test_context;
71
72static test_context test_instance;
73
74static const rtems_task_priority prio_worker[2] = { 2, 1 };
75
76static void
77set_self_prio(rtems_task_priority prio)
78{
79        rtems_status_code sc;
80
81        sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio);
82        assert(sc == RTEMS_SUCCESSFUL);
83}
84
85static rtems_task_priority
86get_self_prio(void)
87{
88        rtems_status_code sc;
89        rtems_task_priority prio;
90
91        sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &prio);
92        assert(sc == RTEMS_SUCCESSFUL);
93
94        return prio;
95}
96
97static void
98worker_task(rtems_task_argument index)
99{
100        test_context *ctx = &test_instance;
101        struct mtx *mtx = &ctx->mtx;
102
103        while (true) {
104                rtems_status_code sc;
105                rtems_event_set events;
106
107                sc = rtems_event_receive(
108                        RTEMS_ALL_EVENTS,
109                        RTEMS_EVENT_ANY | RTEMS_WAIT,
110                        RTEMS_NO_TIMEOUT,
111                        &events
112                );
113                assert(sc == RTEMS_SUCCESSFUL);
114
115                if ((events & EVENT_LOCK) != 0) {
116                        mtx_lock(mtx);
117                        ctx->done[index] = true;
118                }
119
120                if ((events & EVENT_TRY_LOCK) != 0) {
121                        ctx->rv = mtx_trylock(mtx);
122                        ctx->done[index] = true;
123                }
124
125                if ((events & EVENT_UNLOCK) != 0) {
126                        mtx_unlock(mtx);
127                        ctx->done[index] = true;
128                }
129
130                if ((events & EVENT_SLEEP) != 0) {
131                        ctx->rv = mtx_sleep(ctx, mtx, 0, "worker", ctx->timo);
132                        ctx->done[index] = true;
133                }
134        }
135}
136
137static void
138send_events(test_context *ctx, rtems_event_set events, size_t index)
139{
140        rtems_status_code sc;
141
142        sc = rtems_event_send(ctx->worker_task[index], events);
143        assert(sc == RTEMS_SUCCESSFUL);
144}
145
146static void
147start_worker(test_context *ctx)
148{
149        size_t i;
150
151        for (i = 0; i < WORKER_COUNT; ++i) {
152                rtems_status_code sc;
153
154                sc = rtems_task_create(
155                        rtems_build_name('W', 'O', 'R', 'K'),
156                        prio_worker[i],
157                        RTEMS_MINIMUM_STACK_SIZE,
158                        RTEMS_DEFAULT_MODES,
159                        RTEMS_FLOATING_POINT,
160                        &ctx->worker_task[i]
161                );
162                assert(sc == RTEMS_SUCCESSFUL);
163
164                sc = rtems_task_start(
165                        ctx->worker_task[i],
166                        worker_task,
167                        i
168                );
169                assert(sc == RTEMS_SUCCESSFUL);
170        }
171}
172
173static void
174delete_worker(test_context *ctx)
175{
176        size_t i;
177
178        for (i = 0; i < WORKER_COUNT; ++i) {
179                rtems_status_code sc;
180
181                sc = rtems_task_delete(ctx->worker_task[i]);
182                assert(sc == RTEMS_SUCCESSFUL);
183        }
184}
185
186static void
187test_mtx_non_recursive(test_context *ctx)
188{
189        struct mtx *mtx = &ctx->mtx;
190
191        puts("test mtx non-recursive");
192
193        assert(!mtx_initialized(mtx));
194        mtx_init(mtx, "test", NULL, MTX_DEF);
195        assert(mtx_initialized(mtx));
196
197        assert(!mtx_owned(mtx));
198        assert(!mtx_recursed(mtx));
199        mtx_lock(mtx);
200
201        assert(mtx_owned(mtx));
202        assert(!mtx_recursed(mtx));
203
204        mtx_unlock(mtx);
205        assert(!mtx_owned(mtx));
206        assert(!mtx_recursed(mtx));
207
208        mtx_destroy(mtx);
209        assert(!mtx_initialized(mtx));
210}
211
212static void
213test_mtx_recursive(test_context *ctx)
214{
215        struct mtx *mtx = &ctx->mtx;
216
217        puts("test mtx recursive");
218
219        assert(!mtx_initialized(mtx));
220        mtx_init(mtx, "test", NULL, MTX_DEF | MTX_RECURSE);
221        assert(mtx_initialized(mtx));
222
223        assert(!mtx_owned(mtx));
224        assert(!mtx_recursed(mtx));
225        mtx_lock(mtx);
226
227        assert(mtx_owned(mtx));
228        assert(!mtx_recursed(mtx));
229        mtx_lock(mtx);
230
231        assert(mtx_owned(mtx));
232        assert(mtx_recursed(mtx));
233        mtx_lock(mtx);
234
235        assert(mtx_owned(mtx));
236        assert(mtx_recursed(mtx));
237
238        mtx_unlock(mtx);
239        assert(mtx_owned(mtx));
240        assert(mtx_recursed(mtx));
241
242        mtx_unlock(mtx);
243        assert(mtx_owned(mtx));
244        assert(!mtx_recursed(mtx));
245
246        mtx_unlock(mtx);
247        assert(!mtx_owned(mtx));
248        assert(!mtx_recursed(mtx));
249
250        mtx_destroy(mtx);
251        assert(!mtx_initialized(mtx));
252}
253
254static void
255test_mtx_trylock(test_context *ctx)
256{
257        size_t index = 0;
258        struct mtx *mtx = &ctx->mtx;
259        int ok;
260
261        puts("test mtx try lock");
262
263        assert(!mtx_initialized(mtx));
264        mtx_init(mtx, "test", NULL, MTX_DEF);
265        assert(mtx_initialized(mtx));
266
267        assert(!mtx_owned(mtx));
268        assert(!mtx_recursed(mtx));
269        ok = mtx_trylock(mtx);
270        assert(ok != 0);
271        assert(mtx_owned(mtx));
272        assert(!mtx_recursed(mtx));
273
274        mtx_unlock(mtx);
275        assert(!mtx_owned(mtx));
276        assert(!mtx_recursed(mtx));
277
278        assert(!mtx_owned(mtx));
279        assert(!mtx_recursed(mtx));
280        mtx_lock(mtx);
281        assert(mtx_owned(mtx));
282        assert(!mtx_recursed(mtx));
283
284        ctx->done[index] = false;
285        ctx->rv = 1;
286        send_events(ctx, EVENT_TRY_LOCK, index);
287        assert(ctx->done[index]);
288        assert(ctx->rv == 0);
289
290        assert(mtx_owned(mtx));
291        assert(!mtx_recursed(mtx));
292        mtx_unlock(mtx);
293        assert(!mtx_owned(mtx));
294        assert(!mtx_recursed(mtx));
295
296        mtx_destroy(mtx);
297        assert(!mtx_initialized(mtx));
298}
299
300static void
301test_mtx_lock(test_context *ctx)
302{
303        struct mtx *mtx = &ctx->mtx;
304        struct mtx *mtx2 = &ctx->mtx2;
305        size_t low = 0;
306        size_t high = 1;
307
308        puts("test mtx lock");
309
310        assert(!mtx_initialized(mtx));
311        mtx_init(mtx, "test", NULL, MTX_DEF);
312        assert(mtx_initialized(mtx));
313
314        assert(!mtx_initialized(mtx2));
315        mtx_init(mtx2, "test 2", NULL, MTX_DEF);
316        assert(mtx_initialized(mtx2));
317
318        /* Resource count one */
319
320        assert(!mtx_owned(mtx));
321        assert(!mtx_recursed(mtx));
322        mtx_lock(mtx);
323        assert(mtx_owned(mtx));
324        assert(!mtx_recursed(mtx));
325        assert(get_self_prio() == PRIO_MASTER);
326
327        ctx->done[low] = false;
328        ctx->done[high] = false;
329
330        send_events(ctx, EVENT_LOCK, low);
331        assert(!ctx->done[low]);
332        assert(!ctx->done[high]);
333        assert(mtx_owned(mtx));
334        assert(!mtx_recursed(mtx));
335        assert(get_self_prio() == prio_worker[low]);
336
337        send_events(ctx, EVENT_LOCK, high);
338        assert(!ctx->done[low]);
339        assert(!ctx->done[high]);
340        assert(mtx_owned(mtx));
341        assert(!mtx_recursed(mtx));
342        assert(get_self_prio() == prio_worker[high]);
343
344        mtx_unlock(mtx);
345        assert(!ctx->done[low]);
346        assert(ctx->done[high]);
347        assert(!mtx_owned(mtx));
348        assert(!mtx_recursed(mtx));
349        assert(get_self_prio() == PRIO_MASTER);
350
351        ctx->done[high] = false;
352        send_events(ctx, EVENT_UNLOCK, high);
353        assert(ctx->done[low]);
354        assert(ctx->done[high]);
355
356        ctx->done[low] = false;
357        send_events(ctx, EVENT_UNLOCK, low);
358        assert(ctx->done[low]);
359
360        /* Resource count two */
361
362        assert(!mtx_owned(mtx));
363        assert(!mtx_recursed(mtx));
364        mtx_lock(mtx);
365        assert(mtx_owned(mtx));
366        assert(!mtx_recursed(mtx));
367        assert(get_self_prio() == PRIO_MASTER);
368
369        assert(!mtx_owned(mtx2));
370        assert(!mtx_recursed(mtx2));
371        mtx_lock(mtx2);
372        assert(mtx_owned(mtx2));
373        assert(!mtx_recursed(mtx2));
374        assert(get_self_prio() == PRIO_MASTER);
375
376        ctx->done[low] = false;
377        send_events(ctx, EVENT_LOCK, low);
378        assert(!ctx->done[low]);
379        assert(mtx_owned(mtx));
380        assert(!mtx_recursed(mtx));
381        assert(get_self_prio() == prio_worker[low]);
382
383        mtx_unlock(mtx2);
384        assert(!mtx_owned(mtx2));
385        assert(!mtx_recursed(mtx2));
386        assert(get_self_prio() == prio_worker[low]);
387
388        mtx_unlock(mtx);
389        assert(ctx->done[low]);
390        assert(!mtx_owned(mtx));
391        assert(!mtx_recursed(mtx));
392        assert(get_self_prio() == PRIO_MASTER);
393
394        ctx->done[low] = false;
395        send_events(ctx, EVENT_UNLOCK, low);
396        assert(ctx->done[low]);
397
398        mtx_destroy(mtx2);
399        assert(!mtx_initialized(mtx2));
400
401        mtx_destroy(mtx);
402        assert(!mtx_initialized(mtx));
403}
404
405static void
406test_mtx_sleep_with_lock(test_context *ctx)
407{
408        size_t index = 0;
409        struct mtx *mtx = &ctx->mtx;
410
411        puts("test mtx sleep with lock");
412
413        assert(!mtx_initialized(mtx));
414        mtx_init(mtx, "test", NULL, MTX_DEF);
415        assert(mtx_initialized(mtx));
416
417        ctx->done[index] = false;
418        send_events(ctx, EVENT_LOCK, index);
419        assert(ctx->done[index]);
420
421        ctx->done[index] = false;
422        ctx->timo = 0;
423        send_events(ctx, EVENT_SLEEP, index);
424        assert(!ctx->done[index]);
425
426        assert(!mtx_owned(mtx));
427        assert(!mtx_recursed(mtx));
428        mtx_lock(mtx);
429        assert(mtx_owned(mtx));
430        assert(!mtx_recursed(mtx));
431
432        wakeup(ctx);
433        assert(!ctx->done[index]);
434
435        mtx_unlock(mtx);
436        assert(ctx->done[index]);
437        assert(!mtx_owned(mtx));
438        assert(!mtx_recursed(mtx));
439
440        ctx->done[index] = false;
441        send_events(ctx, EVENT_UNLOCK, index);
442        assert(ctx->done[index]);
443
444        mtx_destroy(mtx);
445        assert(!mtx_initialized(mtx));
446}
447
448static void
449test_mtx_sleep_timeout(test_context *ctx)
450{
451        size_t index = 0;
452        struct mtx *mtx = &ctx->mtx;
453        rtems_status_code sc;
454
455        puts("test mtx sleep timeout");
456
457        assert(!mtx_initialized(mtx));
458        mtx_init(mtx, "test", NULL, MTX_DEF);
459        assert(mtx_initialized(mtx));
460
461        ctx->done[index] = false;
462        send_events(ctx, EVENT_LOCK, index);
463        assert(ctx->done[index]);
464
465        ctx->done[index] = false;
466        ctx->timo = 2;
467        send_events(ctx, EVENT_SLEEP, index);
468        assert(!ctx->done[index]);
469
470        sc = rtems_task_wake_after(ctx->timo);
471        assert(sc == RTEMS_SUCCESSFUL);
472        assert(ctx->done[index]);
473
474        ctx->done[index] = false;
475        send_events(ctx, EVENT_UNLOCK, index);
476        assert(ctx->done[index]);
477
478        mtx_destroy(mtx);
479        assert(!mtx_initialized(mtx));
480}
481
482#define PANIC_DO_LOCK 0
483
484#define PANIC_DO_TRYLOCK 1
485
486#define PANIC_DO_UNLOCK 2
487
488static void
489panic_task(rtems_task_argument arg)
490{
491        test_context *ctx = &test_instance;
492        struct mtx *mtx = &ctx->mtx;
493
494        switch (arg) {
495        case PANIC_DO_LOCK:
496                mtx_lock(mtx);
497                mtx_lock(mtx);
498                break;
499        case PANIC_DO_TRYLOCK:
500                mtx_lock(mtx);
501                mtx_trylock(mtx);
502                break;
503        case PANIC_DO_UNLOCK:
504                mtx_unlock(mtx);
505                break;
506        default:
507                assert(0);
508                break;
509        }
510
511        rtems_task_suspend(RTEMS_SELF);
512}
513
514static void
515test_mtx_panic(test_context *ctx)
516{
517        struct mtx *mtx = &ctx->mtx;
518        rtems_status_code sc;
519
520        puts("test mtx panic");
521
522        sc = rtems_task_create(rtems_build_name('P', 'A', 'N', 'I'),
523            get_self_prio(), RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
524            RTEMS_FLOATING_POINT, &ctx->panic_task);
525        assert(sc == RTEMS_SUCCESSFUL);
526
527        assert(!mtx_initialized(mtx));
528        mtx_init(mtx, "test", NULL, MTX_DEF);
529        assert(mtx_initialized(mtx));
530
531        /* Lock recursive panic */
532
533        sc = rtems_task_start(ctx->panic_task, panic_task, PANIC_DO_LOCK);
534        assert(sc == RTEMS_SUCCESSFUL);
535
536        sc = rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
537        assert(sc == RTEMS_SUCCESSFUL);
538
539        sc = rtems_task_restart(ctx->panic_task, PANIC_DO_UNLOCK);
540        assert(sc == RTEMS_SUCCESSFUL);
541
542        sc = rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
543        assert(sc == RTEMS_SUCCESSFUL);
544
545        /* Try lock recursive panic */
546
547        sc = rtems_task_restart(ctx->panic_task, PANIC_DO_TRYLOCK);
548        assert(sc == RTEMS_SUCCESSFUL);
549
550        sc = rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
551        assert(sc == RTEMS_SUCCESSFUL);
552
553        sc = rtems_task_restart(ctx->panic_task, PANIC_DO_UNLOCK);
554        assert(sc == RTEMS_SUCCESSFUL);
555
556        sc = rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
557        assert(sc == RTEMS_SUCCESSFUL);
558
559        /* Unlock not owner panic */
560
561        mtx_lock(mtx);
562
563        sc = rtems_task_restart(ctx->panic_task, PANIC_DO_UNLOCK);
564        assert(sc == RTEMS_SUCCESSFUL);
565
566        sc = rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
567        assert(sc == RTEMS_SUCCESSFUL);
568
569        mtx_unlock(mtx);
570
571        mtx_destroy(mtx);
572        assert(!mtx_initialized(mtx));
573
574        sc = rtems_task_delete(ctx->panic_task);
575        assert(sc == RTEMS_SUCCESSFUL);
576}
577
578static void
579alloc_basic_resources(void)
580{
581        curthread;
582}
583
584static void
585test_main(void)
586{
587        test_context *ctx = &test_instance;
588        rtems_resource_snapshot snapshot_0;
589        rtems_resource_snapshot snapshot_1;
590
591        alloc_basic_resources();
592
593        rtems_resource_snapshot_take(&snapshot_0);
594
595        set_self_prio(PRIO_MASTER);
596        start_worker(ctx);
597
598        rtems_resource_snapshot_take(&snapshot_1);
599
600        test_mtx_non_recursive(ctx);
601        test_mtx_recursive(ctx);
602        test_mtx_trylock(ctx);
603        test_mtx_lock(ctx);
604        test_mtx_panic(ctx);
605
606        assert(rtems_resource_snapshot_check(&snapshot_1));
607
608        test_mtx_sleep_with_lock(ctx);
609        test_mtx_sleep_timeout(ctx);
610
611        delete_worker(ctx);
612
613        assert(rtems_resource_snapshot_check(&snapshot_0));
614
615        exit(0);
616}
617
618#include <rtems/bsd/test/default-init.h>
Note: See TracBrowser for help on using the repository browser.