Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] 多线程情况下触发用户态代码段的缺页异常处理失败 #9854

Open
heyuanjie87 opened this issue Jan 1, 2025 · 4 comments
Labels
bug This PR/issue is a bug in the current code.

Comments

@heyuanjie87
Copy link
Contributor

heyuanjie87 commented Jan 1, 2025

RT-Thread Version

master

Hardware Type/Architectures

qemu-virt64-riscv/k230

Develop Toolchain

GCC

Describe the bug

触发问题的代码

#include <atomic>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
#include <unistd.h>
#include <vector>

using namespace std;

atomic_flag lock_stream = ATOMIC_FLAG_INIT;

void append_number_unlock(int x)
{
    int num;
    cout << "https://www";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".rt-";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << "thread";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".org/";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << setw(3) << setfill('0') << x << endl;
}

void append_number_lock(int x)
{
    while (lock_stream.test_and_set()) {
    }
    int num;
    cout << "https://www";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".rt-";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << "thread";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".org/";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << setw(3) << setfill('0') << x << endl;
    lock_stream.clear();
}

void string_split(const string &str, const char split, vector<string> &res)
{
    if (str == "")
        return;
    // 在字符串末尾也加入分隔符,方便截取最后一段
    string strs = str + split;
    size_t pos  = strs.find(split);

    // 若找不到内容则字符串搜索函数返回 npos
    while (pos != strs.npos) {
        string temp = strs.substr(0, pos);
        res.push_back(temp);
        // 去掉已分割的字符串,在剩下的字符串中进行分割
        strs = strs.substr(pos + 1, strs.size());
        pos  = strs.find(split);
    }
}

int main()
{
    cout << "un_lock" << endl;
    vector<thread> threads_unlock;
    for (int i = 1; i <= 20; ++i)
        threads_unlock.push_back(thread(append_number_unlock, i));
    for (auto &th : threads_unlock)
        th.join();
    cout << "lock" << endl;

    stringstream ss;
    streambuf   *buffer = cout.rdbuf();
    cout.rdbuf(ss.rdbuf());

    vector<thread> threads_lock;
    for (int i = 1; i <= 20; ++i)
        threads_lock.push_back(thread(append_number_lock, i));
    for (auto &th : threads_lock)
        th.join();

    cout.rdbuf(buffer);
    string s(ss.str());
    cout << s << endl;

    vector<string> str_list;
    string_split(s, '\n', str_list);
    bool b = true;
    for (auto str : str_list) {
        cout << str.length() << " ";
        if (str != "")
            if (str.length() != 29) {
                b = false;
            }
    }

    if (b)
        printf("{Test PASS}.\n");
    else
        printf("{Test FAIL}.\n");

    return 0;
}

编译器

针对k230带V指令的gcc13(通用编译器gcc10无法触发)

  • 编译参数: -static

现象描述

当两个线程同时触发同一指令地址的缺页异常时,一个线程成功映射页,另一个线程处理这个异常时被判定为权限问题导致异常处理失败

Other additional context

No response

@BernardXiong
Copy link
Member

可以确认下,k230上不使用v指令时是否存在问题。k230的v指令,感觉在rt-smart支持上并不算完好,导致上下文切换栈深度太深了

@BernardXiong BernardXiong added the bug This PR/issue is a bug in the current code. label Jan 1, 2025
@heyuanjie87
Copy link
Contributor Author

确认过这个示例运行时没执行到v指令,因为我的qemu6不支持v指令,当时qemu运行时编译内核没开v支持也没报错。这里只是一个单纯的缺页处理不完善的问题

@heyuanjie87
Copy link
Contributor Author

用这个示例在k230第一次运行能触发数据区的缺页处理异常(原因同上)

#include <iomanip>
#include <iostream>
#include <mutex>
#include <sstream>
#include <thread>
#include <unistd.h>
#include <vector>

using namespace std;

std::mutex mtx;

void append_number_unlock(int x)
{
    int num;
    cout << "https://www";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".rt-";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << "thread";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".org/";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << setw(3) << setfill('0') << x << endl;
}

void append_number_lock(int x)
{
    mtx.lock();
    int num;
    cout << "https://www";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".rt-";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << "thread";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << ".org/";
    for (int i = 0; i < 1000000; i++)
        num++;
    cout << setw(3) << setfill('0') << x << endl;
    mtx.unlock();
}

void string_split(const string &str, const char split, vector<string> &res)
{
    if (str == "")
        return;
    // 在字符串末尾也加入分隔符,方便截取最后一段
    string strs = str + split;
    size_t pos  = strs.find(split);

    // 若找不到内容则字符串搜索函数返回 npos
    while (pos != strs.npos) {
        string temp = strs.substr(0, pos);
        res.push_back(temp);
        // 去掉已分割的字符串,在剩下的字符串中进行分割
        strs = strs.substr(pos + 1, strs.size());
        pos  = strs.find(split);
    }
}

int main()
{
    cout << "un_lock" << endl;
    vector<thread> threads_unlock;
    for (int i = 1; i <= 20; ++i)
        threads_unlock.push_back(thread(append_number_unlock, i));
    for (auto &th : threads_unlock)
        th.join();
    cout << "lock" << endl;

    stringstream ss;
    streambuf   *buffer = cout.rdbuf();
    cout.rdbuf(ss.rdbuf());

    vector<thread> threads_lock;
    for (int i = 1; i <= 20; ++i)
        threads_lock.push_back(thread(append_number_lock, i));
    for (auto &th : threads_lock)
        th.join();

    cout.rdbuf(buffer);
    string s(ss.str());
    cout << s << endl;

    vector<string> str_list;
    string_split(s, '\n', str_list);
    bool b = true;
    for (auto str : str_list) {
        cout << str.length() << " ";
        if (str != "")
            if (str.length() != 29) {
                b = false;
            }
    }

    if (b)
        printf("{Test PASS}.\n");
    else
        printf("{Test FAIL}.\n");

    return 0;
}

@BernardXiong
Copy link
Member

这个问题是否也可以尝试在aarch64平台上验证下?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This PR/issue is a bug in the current code.
Projects
None yet
Development

No branches or pull requests

2 participants