summaryrefslogtreecommitdiff
path: root/components/mm/utest/test_synchronization.h
blob: 7f813ec1f8fbf5b1581b9e2cf83f4d1f92e0caaf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * Copyright (c) 2006-2023, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-03-24     WangXiaoyao  Complete testcase for synchronization
 */
#ifndef __TEST_SYNCHRONIZATION_H__
#define __TEST_SYNCHRONIZATION_H__

#include "common.h"
#include "semaphore.h"

#ifdef RT_USING_SMP

#define THREAD_CNT RT_CPUS_NR
#define TEST_TIMES 2000
#define PRIO (UTEST_THR_PRIORITY + 1)
/* size of mapping buffer */
#define BUF_SIZE (64ul << 10)

/* engage with sibling */
struct rt_semaphore done;
static semaphore_t sem1[THREAD_CNT / 2];
static semaphore_t sem2[THREAD_CNT / 2];

static void *map(void)
{
    int err;
    int flags = MMF_PREFETCH;
    size_t attr = MMU_MAP_K_RWCB;
    void *vaddr = 0;
    err =
        rt_aspace_map(&rt_kernel_space, &vaddr, BUF_SIZE, attr, flags, &rt_mm_dummy_mapper, 0);
    if (err)
        uassert_true(0);
    return vaddr;
}

static void unmap(void *buf)
{
    int err;
    err =
        rt_aspace_unmap(&rt_kernel_space, buf);
    if (err)
        uassert_true(0);
    return ;
}

static void group1_entry(void *param)
{
    const size_t id = (size_t)param;
    size_t test_times = TEST_TIMES;
    size_t alive = test_times / 10;
    void *buf;

    while (test_times--)
    {
        if (test_times % alive == 0)
            uassert_true(1);

        buf = map();

        memset(buf, 'A' + id, BUF_SIZE);
        /* if other core write to our cache, force the changes to be visible to us */
        rt_hw_dmb();

        if (memtest(buf, 'A' + id, BUF_SIZE))
            uassert_true(0);

        semaphore_signal(&sem1[id]);
        semaphore_wait(&sem2[id]);
        unmap(buf);
    }

    rt_sem_release(&done);
    return;
}

static void group2_entry(void *param)
{
    const size_t id = (size_t)param;
    size_t test_times = TEST_TIMES;
    size_t alive = test_times / 10;
    void *buf;

    while (test_times--)
    {
        if (test_times % alive == 0)
            uassert_true(1);

        semaphore_signal(&sem2[id]);
        semaphore_wait(&sem1[id]);
        buf = map();

        memset(buf, 'a' + id, BUF_SIZE);
        /* if other core write to our cache, force the changes to be visible to us */
        rt_hw_dmb();

        if (memtest(buf, 'a' + id, BUF_SIZE))
            uassert_true(0);

        unmap(buf);
    }

    rt_sem_release(&done);
    return;
}

/**
 * @brief On a smp system, we create at least 4 threads
 * 2 doing map, 2 doing unmapping at the same moment
 */

static void synchronization_tc(void)
{
    rt_thread_t group1[THREAD_CNT / 2];
    rt_thread_t group2[THREAD_CNT / 2];

    rt_sem_init(&done, __func__, 0, RT_IPC_FLAG_FIFO);

    for (size_t i = 0; i < THREAD_CNT / 2; i++)
    {
        char name[RT_NAME_MAX];
        rt_sprintf(name, "grp1_%d", i);
        group1[i] =
            rt_thread_create(name, group1_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10);
        uassert_true(!!group1[i]);
        semaphore_init(&sem1[i], 0);

        uassert_true(!rt_thread_startup(group1[i]));
    }

    for (size_t i = 0; i < THREAD_CNT / 2; i++)
    {
        char name[RT_NAME_MAX];
        rt_sprintf(name, "grp2_%d", i);
        group2[i] =
            rt_thread_create(name, group2_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10);
        uassert_true(!!group2[i]);
        semaphore_init(&sem2[i], 0);

        uassert_true(!rt_thread_startup(group2[i]));
    }

    /* wait all thread exit */
    for (size_t i = 0; i < (THREAD_CNT / 2 * 2); i++)
    {
        rt_sem_take(&done, RT_WAITING_FOREVER);
    }
    LOG_I("all threads exit");
    rt_sem_detach(&done);
}

#else /* RT_USING_SMP */

static void synchronization_tc(void)
{
    uassert_true(1);
}
#endif /* RT_USING_SMP */

#endif /* __TEST_SYNCHRONIZATION_H__ */