forked from Imagelibrary/rtems
793 lines
20 KiB
C
793 lines
20 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/*
|
|
* Copyright (c) 2015, 2016 embedded brains GmbH. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "tmacros.h"
|
|
|
|
#include <sys/lock.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <setjmp.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
const char rtems_test_name[] = "SPSYSLOCK 1";
|
|
|
|
#define US_PER_TICK 10000
|
|
|
|
#define EVENT_MTX_ACQUIRE RTEMS_EVENT_0
|
|
|
|
#define EVENT_MTX_RELEASE RTEMS_EVENT_1
|
|
|
|
#define EVENT_MTX_PRIO_INV RTEMS_EVENT_2
|
|
|
|
#define EVENT_REC_MTX_ACQUIRE RTEMS_EVENT_4
|
|
|
|
#define EVENT_REC_MTX_RELEASE RTEMS_EVENT_5
|
|
|
|
#define EVENT_REC_MTX_PRIO_INV RTEMS_EVENT_6
|
|
|
|
#define EVENT_SEM_WAIT RTEMS_EVENT_7
|
|
|
|
#define EVENT_FUTEX_WAIT RTEMS_EVENT_8
|
|
|
|
#define EVENT_CONDITION_WAIT RTEMS_EVENT_9
|
|
|
|
#define EVENT_CONDITION_WAIT_REC RTEMS_EVENT_10
|
|
|
|
typedef struct {
|
|
rtems_id high[2];
|
|
rtems_id mid;
|
|
rtems_id low;
|
|
struct _Mutex_Control mtx;
|
|
struct _Mutex_recursive_Control rec_mtx;
|
|
struct _Condition_Control cond;
|
|
struct _Semaphore_Control sem;
|
|
struct _Futex_Control futex;
|
|
int val;
|
|
int eno[2];
|
|
int generation[2];
|
|
int current_generation[2];
|
|
jmp_buf deadlock_return_context;
|
|
} test_context;
|
|
|
|
static test_context test_instance;
|
|
|
|
static int generation(test_context *ctx, size_t idx)
|
|
{
|
|
return ++ctx->current_generation[idx];
|
|
}
|
|
|
|
static void send_event(test_context *ctx, size_t idx, rtems_event_set events)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_event_send(ctx->high[idx], events);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
}
|
|
|
|
static void get_abs_timeout(struct timespec *to)
|
|
{
|
|
int rv;
|
|
|
|
rv = clock_gettime(CLOCK_REALTIME, to);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
to->tv_nsec += 2 * US_PER_TICK * 1000;
|
|
if (to->tv_nsec >= 1000000000) {
|
|
++to->tv_sec;
|
|
to->tv_nsec -= 1000000000;
|
|
}
|
|
}
|
|
|
|
static bool eq_tq(
|
|
const struct _Thread_queue_Queue *a,
|
|
const struct _Thread_queue_Queue *b
|
|
)
|
|
{
|
|
return a->_Lock._next_ticket == b->_Lock._next_ticket
|
|
&& a->_Lock._now_serving == b->_Lock._now_serving
|
|
&& a->_heads == b->_heads
|
|
&& a->_owner == b->_owner
|
|
&& a->_name == b->_name;
|
|
}
|
|
|
|
static bool eq_mtx(
|
|
const struct _Mutex_Control *a,
|
|
const struct _Mutex_Control *b
|
|
)
|
|
{
|
|
return eq_tq(&a->_Queue, &b->_Queue);
|
|
}
|
|
|
|
static bool eq_rec_mtx(
|
|
const struct _Mutex_recursive_Control *a,
|
|
const struct _Mutex_recursive_Control *b
|
|
)
|
|
{
|
|
return eq_mtx(&a->_Mutex, &b->_Mutex)
|
|
&& a->_nest_level == b->_nest_level;
|
|
}
|
|
|
|
static bool eq_cond(
|
|
const struct _Condition_Control *a,
|
|
const struct _Condition_Control *b
|
|
)
|
|
{
|
|
return eq_tq(&a->_Queue, &b->_Queue);
|
|
}
|
|
|
|
static bool eq_sem(
|
|
const struct _Semaphore_Control *a,
|
|
const struct _Semaphore_Control *b
|
|
)
|
|
{
|
|
return eq_tq(&a->_Queue, &b->_Queue)
|
|
&& a->_count == b->_count;
|
|
}
|
|
|
|
static bool eq_futex(
|
|
const struct _Futex_Control *a,
|
|
const struct _Futex_Control *b
|
|
)
|
|
{
|
|
return eq_tq(&a->_Queue, &b->_Queue);
|
|
}
|
|
|
|
static void test_initialization(test_context *ctx)
|
|
{
|
|
struct _Mutex_Control mtx = _MUTEX_INITIALIZER;
|
|
struct _Mutex_recursive_Control rec_mtx = _MUTEX_RECURSIVE_INITIALIZER;
|
|
struct _Condition_Control cond = _CONDITION_INITIALIZER;
|
|
struct _Semaphore_Control sem = _SEMAPHORE_INITIALIZER(1);
|
|
struct _Futex_Control futex = _FUTEX_INITIALIZER;
|
|
|
|
_Mutex_Initialize(&ctx->mtx);
|
|
_Mutex_recursive_Initialize(&ctx->rec_mtx);
|
|
_Condition_Initialize(&ctx->cond);
|
|
_Semaphore_Initialize(&ctx->sem, 1);
|
|
_Futex_Initialize(&ctx->futex);
|
|
|
|
rtems_test_assert(eq_mtx(&mtx, &ctx->mtx));
|
|
rtems_test_assert(eq_rec_mtx(&rec_mtx, &ctx->rec_mtx));
|
|
rtems_test_assert(eq_cond(&cond, &ctx->cond));
|
|
rtems_test_assert(eq_sem(&sem, &ctx->sem));
|
|
rtems_test_assert(eq_futex(&futex, &ctx->futex));
|
|
|
|
_Mutex_Destroy(&mtx);
|
|
_Mutex_recursive_Destroy(&rec_mtx);
|
|
_Condition_Destroy(&cond);
|
|
_Semaphore_Destroy(&sem);
|
|
_Futex_Destroy(&futex);
|
|
}
|
|
|
|
static void test_recursive_acquire_normal(test_context *ctx)
|
|
{
|
|
struct _Mutex_Control *mtx = &ctx->mtx;
|
|
size_t idx = 0;
|
|
int eno;
|
|
|
|
eno = _Mutex_Try_acquire(mtx);
|
|
rtems_test_assert(eno == 0);
|
|
|
|
eno = _Mutex_Try_acquire(mtx);
|
|
rtems_test_assert(eno == EBUSY);
|
|
|
|
_Mutex_Release(mtx);
|
|
|
|
eno = _Mutex_Try_acquire(mtx);
|
|
rtems_test_assert(eno == 0);
|
|
|
|
_Mutex_Release(mtx);
|
|
|
|
_Mutex_Acquire(mtx);
|
|
|
|
eno = _Mutex_Try_acquire(mtx);
|
|
rtems_test_assert(eno == EBUSY);
|
|
|
|
_Mutex_Release(mtx);
|
|
|
|
send_event(ctx, idx, EVENT_MTX_ACQUIRE);
|
|
|
|
eno = _Mutex_Try_acquire(mtx);
|
|
rtems_test_assert(eno == EBUSY);
|
|
|
|
send_event(ctx, idx, EVENT_MTX_RELEASE);
|
|
}
|
|
|
|
static void test_recursive_acquire_recursive(test_context *ctx)
|
|
{
|
|
struct _Mutex_recursive_Control *mtx = &ctx->rec_mtx;
|
|
size_t idx = 0;
|
|
int eno;
|
|
|
|
eno = _Mutex_recursive_Try_acquire(mtx);
|
|
rtems_test_assert(eno == 0);
|
|
|
|
_Mutex_recursive_Acquire(mtx);
|
|
|
|
eno = _Mutex_recursive_Try_acquire(mtx);
|
|
rtems_test_assert(eno == 0);
|
|
|
|
_Mutex_recursive_Release(mtx);
|
|
_Mutex_recursive_Release(mtx);
|
|
_Mutex_recursive_Release(mtx);
|
|
|
|
send_event(ctx, idx, EVENT_REC_MTX_ACQUIRE);
|
|
|
|
eno = _Mutex_recursive_Try_acquire(mtx);
|
|
rtems_test_assert(eno == EBUSY);
|
|
|
|
send_event(ctx, idx, EVENT_REC_MTX_RELEASE);
|
|
}
|
|
|
|
static void test_prio_acquire_order(test_context *ctx)
|
|
{
|
|
struct _Mutex_Control *mtx = &ctx->mtx;
|
|
size_t a = 0;
|
|
size_t b = 1;
|
|
int gen_a;
|
|
int gen_b;
|
|
|
|
_Mutex_Acquire(mtx);
|
|
|
|
gen_a = ctx->generation[a];
|
|
gen_b = ctx->generation[b];
|
|
|
|
send_event(ctx, b, EVENT_MTX_ACQUIRE);
|
|
send_event(ctx, a, EVENT_MTX_ACQUIRE);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a);
|
|
rtems_test_assert(ctx->generation[b] == gen_b);
|
|
|
|
_Mutex_Release(mtx);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 1);
|
|
rtems_test_assert(ctx->generation[b] == gen_b);
|
|
|
|
send_event(ctx, a, EVENT_MTX_RELEASE);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 1);
|
|
rtems_test_assert(ctx->generation[b] == gen_b + 1);
|
|
|
|
send_event(ctx, b, EVENT_MTX_RELEASE);
|
|
}
|
|
|
|
static void test_prio_inv_normal(test_context *ctx)
|
|
{
|
|
struct _Mutex_Control *mtx = &ctx->mtx;
|
|
size_t idx = 0;
|
|
int gen;
|
|
|
|
_Mutex_Acquire(mtx);
|
|
gen = ctx->generation[idx];
|
|
send_event(ctx, idx, EVENT_MTX_PRIO_INV);
|
|
rtems_test_assert(ctx->generation[idx] == gen);
|
|
_Mutex_Release(mtx);
|
|
rtems_test_assert(ctx->generation[idx] == gen + 1);
|
|
}
|
|
|
|
static void test_prio_inv_recursive(test_context *ctx)
|
|
{
|
|
struct _Mutex_recursive_Control *mtx = &ctx->rec_mtx;
|
|
size_t idx = 0;
|
|
int gen;
|
|
|
|
_Mutex_recursive_Acquire(mtx);
|
|
gen = ctx->generation[idx];
|
|
send_event(ctx, idx, EVENT_REC_MTX_PRIO_INV);
|
|
rtems_test_assert(ctx->generation[idx] == gen);
|
|
_Mutex_recursive_Release(mtx);
|
|
rtems_test_assert(ctx->generation[idx] == gen + 1);
|
|
}
|
|
|
|
static void test_mtx_timeout_normal(test_context *ctx)
|
|
{
|
|
struct _Mutex_Control *mtx = &ctx->mtx;
|
|
size_t idx = 0;
|
|
struct timespec to;
|
|
int eno;
|
|
|
|
eno = _Mutex_Acquire_timed(mtx, NULL);
|
|
rtems_test_assert(eno == 0);
|
|
_Mutex_Release(mtx);
|
|
|
|
send_event(ctx, idx, EVENT_MTX_ACQUIRE);
|
|
|
|
memset(&to, 0x00, sizeof(to));
|
|
eno = _Mutex_Acquire_timed(mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
memset(&to, 0xff, sizeof(to));
|
|
eno = _Mutex_Acquire_timed(mtx, &to);
|
|
rtems_test_assert(eno == EINVAL);
|
|
get_abs_timeout(&to);
|
|
eno = _Mutex_Acquire_timed(mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
|
|
send_event(ctx, idx, EVENT_MTX_RELEASE);
|
|
}
|
|
|
|
static void test_mtx_timeout_recursive(test_context *ctx)
|
|
{
|
|
struct _Mutex_recursive_Control *mtx = &ctx->rec_mtx;
|
|
size_t idx = 0;
|
|
struct timespec to;
|
|
int eno;
|
|
|
|
eno = _Mutex_recursive_Acquire_timed(mtx, NULL);
|
|
rtems_test_assert(eno == 0);
|
|
eno = _Mutex_recursive_Acquire_timed(mtx, NULL);
|
|
rtems_test_assert(eno == 0);
|
|
_Mutex_recursive_Release(mtx);
|
|
_Mutex_recursive_Release(mtx);
|
|
|
|
send_event(ctx, idx, EVENT_REC_MTX_ACQUIRE);
|
|
|
|
memset(&to, 0x00, sizeof(to));
|
|
eno = _Mutex_recursive_Acquire_timed(mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
memset(&to, 0xff, sizeof(to));
|
|
eno = _Mutex_recursive_Acquire_timed(mtx, &to);
|
|
rtems_test_assert(eno == EINVAL);
|
|
get_abs_timeout(&to);
|
|
eno = _Mutex_recursive_Acquire_timed(mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
|
|
send_event(ctx, idx, EVENT_REC_MTX_RELEASE);
|
|
}
|
|
|
|
static void test_mtx_deadlock(test_context *ctx)
|
|
{
|
|
struct _Mutex_Control *mtx = &ctx->mtx;
|
|
|
|
_Mutex_Acquire(mtx);
|
|
|
|
if (setjmp(ctx->deadlock_return_context) == 0) {
|
|
_Mutex_Acquire(mtx);
|
|
}
|
|
|
|
_Mutex_Release(mtx);
|
|
}
|
|
|
|
static void test_condition(test_context *ctx)
|
|
{
|
|
struct _Condition_Control *cond = &ctx->cond;
|
|
size_t a = 0;
|
|
size_t b = 1;
|
|
int gen_a;
|
|
int gen_b;
|
|
|
|
gen_a = ctx->generation[a];
|
|
gen_b = ctx->generation[b];
|
|
|
|
_Condition_Signal(cond);
|
|
_Condition_Broadcast(cond);
|
|
|
|
send_event(ctx, a, EVENT_CONDITION_WAIT);
|
|
send_event(ctx, b, EVENT_CONDITION_WAIT_REC);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 1);
|
|
rtems_test_assert(ctx->generation[b] == gen_b + 1);
|
|
|
|
_Condition_Signal(cond);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 2);
|
|
rtems_test_assert(ctx->generation[b] == gen_b + 1);
|
|
|
|
_Condition_Signal(cond);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 2);
|
|
rtems_test_assert(ctx->generation[b] == gen_b + 2);
|
|
|
|
send_event(ctx, a, EVENT_CONDITION_WAIT);
|
|
send_event(ctx, b, EVENT_CONDITION_WAIT_REC);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 3);
|
|
rtems_test_assert(ctx->generation[b] == gen_b + 3);
|
|
|
|
_Condition_Broadcast(cond);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 4);
|
|
rtems_test_assert(ctx->generation[b] == gen_b + 4);
|
|
}
|
|
|
|
static void test_condition_timeout(test_context *ctx)
|
|
{
|
|
struct timespec to;
|
|
int eno;
|
|
|
|
_Mutex_Acquire(&ctx->mtx);
|
|
memset(&to, 0x00, sizeof(to));
|
|
eno = _Condition_Wait_timed(&ctx->cond, &ctx->mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
memset(&to, 0xff, sizeof(to));
|
|
eno = _Condition_Wait_timed(&ctx->cond, &ctx->mtx, &to);
|
|
rtems_test_assert(eno == EINVAL);
|
|
get_abs_timeout(&to);
|
|
eno = _Condition_Wait_timed(&ctx->cond, &ctx->mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
_Mutex_Release(&ctx->mtx);
|
|
|
|
_Mutex_recursive_Acquire(&ctx->rec_mtx);
|
|
_Mutex_recursive_Acquire(&ctx->rec_mtx);
|
|
memset(&to, 0x00, sizeof(to));
|
|
eno = _Condition_Wait_recursive_timed(&ctx->cond, &ctx->rec_mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
memset(&to, 0xff, sizeof(to));
|
|
eno = _Condition_Wait_recursive_timed(&ctx->cond, &ctx->rec_mtx, &to);
|
|
rtems_test_assert(eno == EINVAL);
|
|
get_abs_timeout(&to);
|
|
eno = _Condition_Wait_recursive_timed(&ctx->cond, &ctx->rec_mtx, &to);
|
|
rtems_test_assert(eno == ETIMEDOUT);
|
|
_Mutex_recursive_Release(&ctx->rec_mtx);
|
|
_Mutex_recursive_Release(&ctx->rec_mtx);
|
|
}
|
|
|
|
static void test_sem(test_context *ctx)
|
|
{
|
|
struct _Semaphore_Control *sem = &ctx->sem;
|
|
size_t idx = 0;
|
|
int gen;
|
|
|
|
_Semaphore_Wait(sem);
|
|
gen = ctx->generation[idx];
|
|
send_event(ctx, idx, EVENT_SEM_WAIT);
|
|
rtems_test_assert(ctx->generation[idx] == gen);
|
|
_Semaphore_Post(sem);
|
|
rtems_test_assert(ctx->generation[idx] == gen + 1);
|
|
_Semaphore_Post(sem);
|
|
}
|
|
|
|
static void test_sem_prio_wait_order(test_context *ctx)
|
|
{
|
|
struct _Semaphore_Control *sem = &ctx->sem;
|
|
size_t a = 0;
|
|
size_t b = 1;
|
|
int gen_a;
|
|
int gen_b;
|
|
|
|
_Semaphore_Wait(sem);
|
|
|
|
gen_a = ctx->generation[a];
|
|
gen_b = ctx->generation[b];
|
|
|
|
send_event(ctx, b, EVENT_SEM_WAIT);
|
|
send_event(ctx, a, EVENT_SEM_WAIT);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a);
|
|
rtems_test_assert(ctx->generation[b] == gen_b);
|
|
|
|
_Semaphore_Post(sem);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 1);
|
|
rtems_test_assert(ctx->generation[b] == gen_b);
|
|
|
|
_Semaphore_Post(sem);
|
|
|
|
rtems_test_assert(ctx->generation[a] == gen_a + 1);
|
|
rtems_test_assert(ctx->generation[b] == gen_b + 1);
|
|
}
|
|
|
|
static void test_futex(test_context *ctx)
|
|
{
|
|
struct _Futex_Control *futex = &ctx->futex;
|
|
size_t a = 0;
|
|
size_t b = 1;
|
|
int eno;
|
|
int woken;
|
|
|
|
eno = _Futex_Wait(futex, &ctx->val, 1);
|
|
rtems_test_assert(eno == EWOULDBLOCK);
|
|
|
|
woken = _Futex_Wake(futex, 0);
|
|
rtems_test_assert(woken == 0);
|
|
|
|
woken = _Futex_Wake(futex, 1);
|
|
rtems_test_assert(woken == 0);
|
|
|
|
ctx->val = 1;
|
|
|
|
ctx->eno[a] = -1;
|
|
send_event(ctx, a, EVENT_FUTEX_WAIT);
|
|
rtems_test_assert(ctx->eno[a] == -1);
|
|
|
|
woken = _Futex_Wake(futex, INT_MAX);
|
|
rtems_test_assert(woken == 1);
|
|
rtems_test_assert(ctx->eno[a] == 0);
|
|
|
|
ctx->eno[a] = -1;
|
|
ctx->eno[b] = -1;
|
|
send_event(ctx, a, EVENT_FUTEX_WAIT);
|
|
send_event(ctx, b, EVENT_FUTEX_WAIT);
|
|
rtems_test_assert(ctx->eno[a] == -1);
|
|
rtems_test_assert(ctx->eno[b] == -1);
|
|
|
|
woken = _Futex_Wake(futex, 1);
|
|
rtems_test_assert(woken == 1);
|
|
rtems_test_assert(ctx->eno[a] == 0);
|
|
rtems_test_assert(ctx->eno[b] == -1);
|
|
|
|
woken = _Futex_Wake(futex, 1);
|
|
rtems_test_assert(woken == 1);
|
|
rtems_test_assert(ctx->eno[a] == 0);
|
|
rtems_test_assert(ctx->eno[b] == 0);
|
|
|
|
ctx->eno[a] = -1;
|
|
ctx->eno[b] = -1;
|
|
send_event(ctx, a, EVENT_FUTEX_WAIT);
|
|
send_event(ctx, b, EVENT_FUTEX_WAIT);
|
|
rtems_test_assert(ctx->eno[a] == -1);
|
|
rtems_test_assert(ctx->eno[b] == -1);
|
|
|
|
woken = _Futex_Wake(futex, 2);
|
|
rtems_test_assert(woken == 2);
|
|
rtems_test_assert(ctx->eno[a] == 0);
|
|
rtems_test_assert(ctx->eno[b] == 0);
|
|
}
|
|
|
|
static void test_sched(void)
|
|
{
|
|
rtems_test_assert(_Sched_Index() == 0);
|
|
rtems_test_assert(_Sched_Name_to_index("", 0) == -1);
|
|
rtems_test_assert(_Sched_Name_to_index("b", 1) == -1);
|
|
rtems_test_assert(_Sched_Name_to_index("bl", 2) == -1);
|
|
rtems_test_assert(_Sched_Name_to_index("blu", 3) == -1);
|
|
rtems_test_assert(_Sched_Name_to_index("blue", 4) == 0);
|
|
rtems_test_assert(_Sched_Name_to_index("blueX", 5) == 0);
|
|
rtems_test_assert(_Sched_Processor_count(-1) == 0);
|
|
rtems_test_assert(_Sched_Processor_count(0) == 1);
|
|
rtems_test_assert(_Sched_Processor_count(1) == 0);
|
|
}
|
|
|
|
static void mid_task(rtems_task_argument arg)
|
|
{
|
|
rtems_test_assert(0);
|
|
}
|
|
|
|
static void high_task(rtems_task_argument idx)
|
|
{
|
|
test_context *ctx = &test_instance;
|
|
rtems_status_code sc;
|
|
|
|
if (idx == 0) {
|
|
sc = rtems_task_start(ctx->mid, mid_task, 0);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_suspend(ctx->mid);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
}
|
|
|
|
while (true) {
|
|
rtems_event_set events;
|
|
|
|
sc = rtems_event_receive(
|
|
RTEMS_ALL_EVENTS,
|
|
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
|
RTEMS_NO_TIMEOUT,
|
|
&events
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
if ((events & EVENT_MTX_ACQUIRE) != 0) {
|
|
_Mutex_Acquire(&ctx->mtx);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
}
|
|
|
|
if ((events & EVENT_MTX_RELEASE) != 0) {
|
|
_Mutex_Release(&ctx->mtx);
|
|
}
|
|
|
|
if ((events & EVENT_MTX_PRIO_INV) != 0) {
|
|
sc = rtems_task_resume(ctx->mid);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
_Mutex_Acquire(&ctx->mtx);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
_Mutex_Release(&ctx->mtx);
|
|
|
|
sc = rtems_task_suspend(ctx->mid);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
}
|
|
|
|
if ((events & EVENT_REC_MTX_ACQUIRE) != 0) {
|
|
_Mutex_recursive_Acquire(&ctx->rec_mtx);
|
|
}
|
|
|
|
if ((events & EVENT_REC_MTX_RELEASE) != 0) {
|
|
_Mutex_recursive_Release(&ctx->rec_mtx);
|
|
}
|
|
|
|
if ((events & EVENT_REC_MTX_PRIO_INV) != 0) {
|
|
sc = rtems_task_resume(ctx->mid);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
_Mutex_recursive_Acquire(&ctx->rec_mtx);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
_Mutex_recursive_Release(&ctx->rec_mtx);
|
|
|
|
sc = rtems_task_suspend(ctx->mid);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
}
|
|
|
|
if ((events & EVENT_SEM_WAIT) != 0) {
|
|
_Semaphore_Wait(&ctx->sem);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
}
|
|
|
|
if ((events & EVENT_FUTEX_WAIT) != 0) {
|
|
ctx->eno[idx] = _Futex_Wait(&ctx->futex, &ctx->val, 1);
|
|
}
|
|
|
|
if ((events & EVENT_CONDITION_WAIT) != 0) {
|
|
_Mutex_Acquire(&ctx->mtx);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
_Condition_Wait(&ctx->cond, &ctx->mtx);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
_Mutex_Release(&ctx->mtx);
|
|
}
|
|
|
|
if ((events & EVENT_CONDITION_WAIT_REC) != 0) {
|
|
_Mutex_recursive_Acquire(&ctx->rec_mtx);
|
|
_Mutex_recursive_Acquire(&ctx->rec_mtx);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
_Condition_Wait_recursive(&ctx->cond, &ctx->rec_mtx);
|
|
ctx->generation[idx] = generation(ctx, idx);
|
|
_Mutex_recursive_Release(&ctx->rec_mtx);
|
|
_Mutex_recursive_Release(&ctx->rec_mtx);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test(void)
|
|
{
|
|
test_context *ctx = &test_instance;
|
|
rtems_status_code sc;
|
|
|
|
test_initialization(ctx);
|
|
|
|
ctx->low = rtems_task_self();
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name('M', 'I', 'D', ' '),
|
|
3,
|
|
RTEMS_MINIMUM_STACK_SIZE,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&ctx->mid
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name('H', 'I', 'G', '0'),
|
|
1,
|
|
RTEMS_MINIMUM_STACK_SIZE,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&ctx->high[0]
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_start(ctx->high[0], high_task, 0);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name('H', 'I', 'G', '1'),
|
|
2,
|
|
RTEMS_MINIMUM_STACK_SIZE,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&ctx->high[1]
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_start(ctx->high[1], high_task, 1);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
test_recursive_acquire_normal(ctx);
|
|
test_recursive_acquire_recursive(ctx);
|
|
test_prio_acquire_order(ctx);
|
|
test_prio_inv_normal(ctx);
|
|
test_prio_inv_recursive(ctx);
|
|
test_mtx_timeout_normal(ctx);
|
|
test_mtx_timeout_recursive(ctx);
|
|
test_mtx_deadlock(ctx);
|
|
test_condition(ctx);
|
|
test_condition_timeout(ctx);
|
|
test_sem(ctx);
|
|
test_sem_prio_wait_order(ctx);
|
|
test_futex(ctx);
|
|
test_sched();
|
|
|
|
sc = rtems_task_delete(ctx->mid);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_delete(ctx->high[0]);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_delete(ctx->high[1]);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
_Mutex_Destroy(&ctx->mtx);
|
|
_Mutex_recursive_Destroy(&ctx->rec_mtx);
|
|
_Condition_Destroy(&ctx->cond);
|
|
_Semaphore_Destroy(&ctx->sem);
|
|
_Futex_Destroy(&ctx->futex);
|
|
}
|
|
|
|
static void Init(rtems_task_argument arg)
|
|
{
|
|
TEST_BEGIN();
|
|
|
|
test();
|
|
|
|
TEST_END();
|
|
rtems_test_exit(0);
|
|
}
|
|
|
|
static void fatal_extension(
|
|
rtems_fatal_source source,
|
|
bool always_set_to_false,
|
|
rtems_fatal_code error
|
|
)
|
|
{
|
|
|
|
if (
|
|
source == INTERNAL_ERROR_CORE
|
|
&& !always_set_to_false
|
|
&& error == INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK
|
|
) {
|
|
test_context *ctx = &test_instance;
|
|
|
|
longjmp(ctx->deadlock_return_context, 1);
|
|
}
|
|
}
|
|
|
|
#define CONFIGURE_MICROSECONDS_PER_TICK US_PER_TICK
|
|
|
|
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
|
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
|
|
|
|
#define CONFIGURE_MAXIMUM_TASKS 4
|
|
|
|
#define CONFIGURE_INITIAL_EXTENSIONS \
|
|
{ .fatal = fatal_extension }, \
|
|
RTEMS_TEST_INITIAL_EXTENSION
|
|
|
|
#define CONFIGURE_INIT_TASK_PRIORITY 4
|
|
#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
|
|
|
|
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
|
|
|
#define CONFIGURE_SCHEDULER_NAME rtems_build_name('b', 'l', 'u', 'e')
|
|
|
|
#define CONFIGURE_INIT
|
|
|
|
#include <rtems/confdefs.h>
|