From faa0e2134f55ac91570c397634987629aed0d24f Mon Sep 17 00:00:00 2001 From: zhangzheng <1358745329@qq.comwq> Date: Mon, 20 Nov 2023 16:17:58 +0800 Subject: [PATCH] =?UTF-8?q?futex=E6=94=AF=E6=8C=81=E8=B6=85=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 6 +- install.sh | 496 ++++++++++++++++++ kconfig.cmake | 1 + mkrtos_knl/drivers/stm32f1x/systick/systick.c | 4 +- mkrtos_knl/drivers/stm32f2x/systick/systick.c | 5 +- mkrtos_knl/inc/knl/access.h | 5 + mkrtos_knl/inc/knl/futex.h | 2 +- mkrtos_knl/knl/access.c | 32 ++ mkrtos_knl/knl/futex.c | 147 ++++-- mkrtos_knl/knl/ipc.c | 2 +- mkrtos_script/build.sh | 9 +- .../kconfigfunctions.cpython-38.pyc | Bin 0 -> 19172 bytes .../__pycache__/kconfiglib.cpython-38.pyc | Bin 0 -> 159413 bytes .../lib/libc_backend/src/futex_backend.c | 6 +- .../lib/libc_backend/src/sys_backend.c | 9 +- mkrtos_user/lib/sys/inc/u_futex.h | 2 +- mkrtos_user/lib/sys/src/u_futex.c | 2 +- .../server/init/src/test/pthread_lock_test.c | 37 +- 18 files changed, 679 insertions(+), 86 deletions(-) create mode 100644 install.sh create mode 100644 mkrtos_knl/inc/knl/access.h create mode 100644 mkrtos_knl/knl/access.c create mode 100644 mkrtos_tool/kconfig/__pycache__/kconfigfunctions.cpython-38.pyc create mode 100644 mkrtos_tool/kconfig/__pycache__/kconfiglib.cpython-38.pyc diff --git a/.vscode/launch.json b/.vscode/launch.json index 04fe2fa5f..461e21b5a 100755 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -45,9 +45,9 @@ "environment": [], "externalConsole": false, // "miDebuggerPath": "/opt/homebrew/bin/arm-none-eabi-gdb", - "miDebuggerPath": "/Users/zhangzheng/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb", - // "miDebuggerPath": "/home/zhangzheng/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-gdb", - "miDebuggerServerAddress": "127.0.0.1:3333", + // "miDebuggerPath": "/Users/zhangzheng/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb", + "miDebuggerPath": "/home/zhangzheng/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-gdb", + "miDebuggerServerAddress": "127.0.0.1:3334", "MIMode": "gdb", "setupCommands": [ { diff --git a/install.sh b/install.sh new file mode 100644 index 000000000..419b85bef --- /dev/null +++ b/install.sh @@ -0,0 +1,496 @@ +#!/bin/bash +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin +export PATH +LANG=en_US.UTF-8 + + +echo " ++---------------------------------------------------------------------- +| Bt-WebPanel 5.x FOR Ubuntu/Debian ++---------------------------------------------------------------------- +| Copyright © 2015-2018 BT-SOFT(http://www.bt.cn) All rights reserved. ++---------------------------------------------------------------------- +| The WebPanel URL will be http://SERVER_IP:8888 when installed. ++---------------------------------------------------------------------- +" +deepinSys=`cat /etc/issue` +if [[ "${deepinSys}" =~ eepin ]]; then + isroot='' + if [ `whoami` != "root" ];then + isroot='sudo ' + fi + if [ -f "/etc/init.d/bt" ]; then + password=`${isroot}cat /www/server/panel/default.pl` + port=`${isroot}cat /www/server/panel/data/port.pl` + echo -e "==================================================================" + echo -e "Bt-Panel: http://localhost:$port" + echo -e "默认账户: admin" + echo -e "默认密码: $password" + echo -e "==================================================================" + echo -e "正在尝试打开浏览器..." + if [ -f "/opt/google/chrome/chrome" ]; then + ${isroot}/opt/google/chrome/chrome --no-sandbox http://localhost:$port + exit; + fi + if [ -f "/usr/lib/firefox/firefox" ]; then + /usr/lib/firefox/firefox http://localhost:$port + exit; + fi + echo -e "找不到chrome/firefox浏览器,请自行打开浏览器访问宝塔面板: http://loshost:$port" + exit; + + fi +fi +if [ `whoami` != "root" ];then + echo -e "\033[31mError: Please run the script with root privileges on Ubuntu, for example: sudo bash install.sh\033[0m"; + exit; +fi + +#自动选择下载节点 +get_node_url(){ + nodes=(http://125.88.182.172:5880 http://103.224.251.67 http://128.1.164.196 http://download.bt.cn); + i=1; + if [ ! -f /bin/curl ];then + if [ -f /usr/local/curl/bin/curl ];then + ln -sf /usr/local/curl/bin/curl /bin/curl + else + yum install curl -y + fi + fi + for node in ${nodes[@]}; + do + start=`date +%s.%N` + result=`curl -sS --connect-timeout 3 -m 60 $node/check.txt` + if [ $result = 'True' ];then + end=`date +%s.%N` + start_s=`echo $start | cut -d '.' -f 1` + start_ns=`echo $start | cut -d '.' -f 2` + end_s=`echo $end | cut -d '.' -f 1` + end_ns=`echo $end | cut -d '.' -f 2` + time_micro=$(( (10#$end_s-10#$start_s)*1000000 + (10#$end_ns/1000 - 10#$start_ns/1000) )) + time_ms=$(($time_micro/1000)) + values[$i]=$time_ms; + urls[$time_ms]=$node + i=$(($i+1)) + fi + done + j=5000 + for n in ${values[@]}; + do + if [ $j -gt $n ];then + j=$n + fi + done + if [ $j = 5000 ];then + NODE_URL='http://download.bt.cn'; + else + NODE_URL=${urls[$j]} + fi + +} + +echo '---------------------------------------------'; +echo "Selected download node..."; +get_node_url +download_Url=$NODE_URL +echo "Download node: $download_Url"; +echo '---------------------------------------------'; +setup_path=/www +port='8888' +if [ -f $setup_path/server/panel/data/port.pl ];then + port=`cat $setup_path/server/panel/data/port.pl` +fi + +while [ "$go" != 'y' ] && [ "$go" != 'n' ] +do + read -p "Do you want to install Bt-Panel to the $setup_path directory now?(y/n): " go; +done + +if [ "$go" = 'n' ];then + exit; +fi +startTime=`date +%s` + +#数据盘自动分区 +fdiskP(){ + + for i in `cat /proc/partitions|grep -v name|grep -v ram|awk '{print $4}'|grep -v '^$'|grep -v '[0-9]$'|grep -e 'vd' -e 'sd' -e 'xv'`; + do + #判断/www是否被挂载 + isR=`df -P|grep $setup_path` + if [ "$isR" != "" ];then + echo 'Warning: The /www directory has been mounted.' + return; + fi + #判断是否存在未分区磁盘 + isP=`fdisk -l /dev/$i |grep -v 'bytes'|grep "$i[1-9]*"` + if [ "$isP" = "" ];then + #开始分区 + fdisk -S 56 /dev/$i << EOF +n +p +1 + + +wq +EOF + + sleep 5 + #检查是否分区成功 + checkP=`fdisk -l /dev/$i|grep "/dev/${i}1"` + if [ "$checkP" != "" ];then + #格式化分区 + mkfs.ext4 /dev/${i}1 + mkdir $setup_path + #挂载分区 + sed -i "/\/dev\/${i}1/d" /etc/fstab + echo "/dev/${i}1 $setup_path ext4 defaults 0 0" >> /etc/fstab + mount -a + df -h + fi + else + #判断是否存在Windows磁盘分区 + isN=`fdisk -l /dev/$i|grep -v 'bytes'|grep -v "NTFS"|grep -v "FAT32"` + if [ "$isN" = "" ];then + echo 'Warning: The Windows partition was detected. For your data security, Mount manually.'; + return; + fi + + #挂载已有分区 + checkR=`df -P|grep "/dev/$i"` + if [ "$checkR" = "" ];then + mkdir $setup_path + sed -i "/\/dev\/${i}1/d" /etc/fstab + echo "/dev/${i}1 $setup_path ext4 defaults 0 0" >> /etc/fstab + mount -a + df -h + fi + + #清理不可写分区 + echo 'True' > $setup_path/checkD.pl + if [ ! -f $setup_path/checkD.pl ];then + sed -i "/\/dev\/${i}1/d" /etc/fstab + mount -a + df -h + else + rm -f $setup_path/checkD.pl + fi + fi + done +} +#fdiskP + +ln -sf bash /bin/sh +apt-get install ruby -y +apt-get update -y +apt-get install lsb-release -y +#apt-get install ntp ntpdate -y +#/etc/init.d/ntp stop +#update-rc.d ntp remove +#cat >>~/.profile<&1|awk '{print $2}') +pVersion=${tmp:0:3} + +Install_setuptools() +{ + if [ ! -f "/usr/bin/easy_install" ];then + wget -O setuptools-33.1.1.zip $download_Url/install/src/setuptools-33.1.1.zip -T 10 + unzip setuptools-33.1.1.zip + rm -f setuptools-33.1.1.zip + cd setuptools-33.1.1 + python setup.py install + cd .. + rm -rf setuptools-33.1.1 + fi + + if [ ! -f "/usr/bin/easy_install" ];then + echo '================================================='; + echo -e "\033[31msetuptools installation failed. \033[0m"; + exit; + fi +} +Install_Pillow() +{ + isSetup=`python -m PIL 2>&1|grep package` + if [ "$isSetup" = "" ];then + wget -O Pillow-3.2.0.zip $download_Url/install/src/Pillow-3.2.0.zip -T 10 + unzip Pillow-3.2.0.zip + rm -f Pillow-3.2.0.zip + cd Pillow-3.2.0 + python setup.py install + cd .. + rm -rf Pillow-3.2.0 + fi + isSetup=`python -m PIL 2>&1|grep package` + if [ "$isSetup" = "" ];then + echo '================================================='; + echo -e "\033[31mPillow installation failed. \033[0m"; + exit; + fi +} + +Install_psutil() +{ + isSetup=`python -m psutil 2>&1|grep package` + if [ "$isSetup" = "" ];then + wget -O psutil-5.2.2.tar.gz $download_Url/install/src/psutil-5.2.2.tar.gz -T 10 + tar xvf psutil-5.2.2.tar.gz + rm -f psutil-5.2.2.tar.gz + cd psutil-5.2.2 + python setup.py install + cd .. + rm -rf psutil-5.2.2 + fi + isSetup=`python -m psutil 2>&1|grep package` + if [ "$isSetup" = "" ];then + echo '================================================='; + echo -e "\033[31mpsutil installation failed. \033[0m"; + exit; + fi +} + +Install_mysqldb() +{ + isSetup=`python -m MySQLdb 2>&1|grep package` + if [ "$isSetup" = "" ];then + wget -O MySQL-python-1.2.5.zip $download_Url/install/src/MySQL-python-1.2.5.zip -T 10 + unzip MySQL-python-1.2.5.zip + rm -f MySQL-python-1.2.5.zip + cd MySQL-python-1.2.5 + python setup.py install + cd .. + rm -rf MySQL-python-1.2.5 + fi + +} + +Install_chardet() +{ + isSetup=`python -m chardet 2>&1|grep package` + if [ "$isSetup" = "" ];then + wget -O chardet-2.3.0.tar.gz $download_Url/install/src/chardet-2.3.0.tar.gz -T 10 + tar xvf chardet-2.3.0.tar.gz + rm -f chardet-2.3.0.tar.gz + cd chardet-2.3.0 + python setup.py install + cd .. + rm -rf chardet-2.3.0 + fi + isSetup=`python -m chardet 2>&1|grep package` + if [ "$isSetup" = "" ];then + echo '================================================='; + echo -e "\033[31mchardet installation failed. \033[0m"; + exit; + fi +} + +Install_webpy() +{ + isSetup=`python -m web 2>&1|grep package` + if [ "$isSetup" = "" ];then + wget -O web.py-0.38.tar.gz $download_Url/install/src/web.py-0.38.tar.gz -T 10 + tar xvf web.py-0.38.tar.gz + rm -f web.py-0.38.tar.gz + cd web.py-0.38 + python setup.py install + cd .. + rm -rf web.py-0.38 + fi + + isSetup=`python -m web 2>&1|grep package` + if [ "$isSetup" = "" ];then + echo '================================================='; + echo -e "\033[31mweb.py installation failed. \033[0m"; + exit; + fi +} +pipArg='' + + +pip install setuptools +#pip install --upgrade pip $pipArg +pip install psutil chardet web.py virtualenv Pillow $pipArg + + +Install_Pillow +Install_psutil +if [ -f /www/server/mysql/bin/mysql ]; then + pip install mysql-python + Install_mysqldb +fi +Install_chardet +Install_webpy + +mkdir -p $setup_path/server/panel/logs +mkdir -p $setup_path/server/panel/vhost/apache +mkdir -p $setup_path/server/panel/vhost/nginx +mkdir -p $setup_path/server/panel/vhost/rewrite +wget -O $setup_path/server/panel/certbot-auto $download_Url/install/certbot-auto.init -T 5 +chmod +x $setup_path/server/panel/certbot-auto + + +if [ -f '/etc/init.d/bt' ];then + /etc/init.d/bt stop +fi + +mkdir -p /www/server +mkdir -p /www/wwwroot +mkdir -p /www/wwwlogs +mkdir -p /www/backup/database +mkdir -p /www/backup/site + +wget -O panel.zip $download_Url/install/src/panel.zip -T 10 +wget -O /etc/init.d/bt $download_Url/install/src/bt.init -T 10 +if [ -f "$setup_path/server/panel/data/default.db" ];then + if [ -d "/$setup_path/server/panel/old_data" ];then + rm -rf $setup_path/server/panel/old_data + fi + mkdir -p $setup_path/server/panel/old_data + mv -f $setup_path/server/panel/data/default.db $setup_path/server/panel/old_data/default.db + mv -f $setup_path/server/panel/data/system.db $setup_path/server/panel/old_data/system.db + mv -f $setup_path/server/panel/data/aliossAs.conf $setup_path/server/panel/old_data/aliossAs.conf + mv -f $setup_path/server/panel/data/qiniuAs.conf $setup_path/server/panel/old_data/qiniuAs.conf + mv -f $setup_path/server/panel/data/iplist.txt $setup_path/server/panel/old_data/iplist.txt + mv -f $setup_path/server/panel/data/port.pl $setup_path/server/panel/old_data/port.pl +fi + +unzip -o panel.zip -d $setup_path/server/ > /dev/null + +if [ -d "$setup_path/server/panel/old_data" ];then + mv -f $setup_path/server/panel/old_data/default.db $setup_path/server/panel/data/default.db + mv -f $setup_path/server/panel/old_data/system.db $setup_path/server/panel/data/system.db + mv -f $setup_path/server/panel/old_data/aliossAs.conf $setup_path/server/panel/data/aliossAs.conf + mv -f $setup_path/server/panel/old_data/qiniuAs.conf $setup_path/server/panel/data/qiniuAs.conf + mv -f $setup_path/server/panel/old_data/iplist.txt $setup_path/server/panel/data/iplist.txt + mv -f $setup_path/server/panel/old_data/port.pl $setup_path/server/panel/data/port.pl + + if [ -d "/$setup_path/server/panel/old_data" ];then + rm -rf $setup_path/server/panel/old_data + fi +fi + +rm -f panel.zip + +if [ ! -f $setup_path/server/panel/tools.py ];then + echo -e "\033[31mERROR: Failed to download, please try again!\033[0m"; + echo '============================================' + exit; +fi + +rm -f $setup_path/server/panel/class/*.pyc +rm -f $setup_path/server/panel/*.pyc +python -m compileall $setup_path/server/panel +#rm -f $setup_path/server/panel/class/*.py +#rm -f $setup_path/server/panel/*.py + +chmod 777 /tmp +chmod +x /etc/init.d/bt +update-rc.d bt defaults +chmod -R 600 $setup_path/server/panel +chmod +x $setup_path/server/panel/certbot-auto +chmod -R +x $setup_path/server/panel/script +echo "$port" > $setup_path/server/panel/data/port.pl +/etc/init.d/bt start +password=`cat /dev/urandom | head -n 16 | md5sum | head -c 8` +cd $setup_path/server/panel/ +python tools.py username +username=`python tools.pyc panel $password` +cd ~ +echo "$password" > $setup_path/server/panel/default.pl +chmod 600 $setup_path/server/panel/default.pl + +isStart=`ps aux |grep 'python main.pyc'|grep -v grep|awk '{print $2}'` +if [ "$isStart" == '' ];then + echo -e "\033[31mERROR: The BT-Panel service startup failed.\033[0m"; + echo '============================================' + exit; +fi + +if [ ! -f "/usr/bin/ufw" ];then + apt-get install -y ufw +fi + +if [ -f "/usr/sbin/ufw" ];then + ufw allow 888,20,21,22,80,$port/tcp + ufw allow 39000:40000/tcp + ufw_status=`ufw status` + echo y|ufw enable + ufw default deny + ufw reload +fi +pip install web.py==0.39 +pip install psutil chardet psutil virtualenv $pipArg +if [ ! -d '/etc/letsencrypt' ];then + + mkdir -p /var/spool/cron + if [ ! -f '/var/spool/cron/crontabs/root' ];then + echo '' > /var/spool/cron/crontabs/root + chmod 600 /var/spool/cron/crontabs/root + fi + isCron=`cat /var/spool/cron/crontabs/root|grep certbot.log` + if [ "${isCron}" == "" ];then + echo "30 2 * * * $setup_path/server/panel/certbot-auto renew >> $setup_path/server/panel/logs/certbot.log" >> /var/spool/cron/crontabs/root + chown 600 /var/spool/cron/crontabs/root + fi + service cron restart + nohup $setup_path/server/panel/certbot-auto -n > /tmp/certbot-auto.log 2>&1 & +fi +if [[ "${deepinSys}" =~ eepin ]]; then + address="localhost" +else + address=`curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress` + + if [ "$address" == '0.0.0.0' ] || [ "$address" == '' ];then + isHosts=`cat /etc/hosts|grep 'www.bt.cn'` + if [ "$isHosts" == '' ];then + echo "" >> /etc/hosts + echo "125.88.182.170 www.bt.cn" >> /etc/hosts + address=`curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress` + if [ "$address" == '' ];then + sed -i "/bt.cn/d" /etc/hosts + fi + fi + fi + + ipCheck=`python -c "import re; print re.match('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$','$address')"` + if [ "$address" == "None" ];then + address="SERVER_IP" + fi + if [ "$address" != "SERVER_IP" ];then + echo "$address" > $setup_path/server/panel/data/iplist.txt + fi +fi + +curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/SetupCount?type=Linux\&o=$1 > /dev/null 2>&1 +if [ $1 != "" ];then + echo $1 > /www/server/panel/data/o.pl + cd /www/server/panel + python tools.py o +fi + +echo -e "==================================================================" +echo -e "\033[32mCongratulations! Install succeeded!\033[0m" +echo -e "==================================================================" +echo -e "Bt-Panel: http://$address:$port" +echo -e "username: $username" +echo -e "password: $password" +echo -e "\033[33mWarning:\033[0m" +echo -e "\033[33mIf you cannot access the panel, \033[0m" +echo -e "\033[33mrelease the following port (8888|888|80|443|20|21) in the security group\033[0m" +echo -e "==================================================================" + +endTime=`date +%s` +((outTime=($endTime-$startTime)/60)) +echo -e "Time consumed:\033[32m $outTime \033[0mMinute!" +rm -f install.sh diff --git a/kconfig.cmake b/kconfig.cmake index 5eecee5a3..6fdf7213f 100644 --- a/kconfig.cmake +++ b/kconfig.cmake @@ -10,6 +10,7 @@ message( ${CMAKE_SOURCE_DIR}/build/log.txt "\n" ${CMAKE_SOURCE_DIR}/build/.config "\n" ) + execute_process( COMMAND ${PYTHON_EXECUTABLE} diff --git a/mkrtos_knl/drivers/stm32f1x/systick/systick.c b/mkrtos_knl/drivers/stm32f1x/systick/systick.c index 14e89f6f0..7d7b97e1d 100755 --- a/mkrtos_knl/drivers/stm32f1x/systick/systick.c +++ b/mkrtos_knl/drivers/stm32f1x/systick/systick.c @@ -12,9 +12,9 @@ umword_t sys_tick_cnt_get(void) void SysTick_Handler(void) { - // 进行上下文切换 thread_sched(); - timeout_times_tick(); sys_tick_cnt++; + timeout_times_tick(); + futex_timeout_times_tick(); } diff --git a/mkrtos_knl/drivers/stm32f2x/systick/systick.c b/mkrtos_knl/drivers/stm32f2x/systick/systick.c index e0a3e5eb9..89d65a32e 100755 --- a/mkrtos_knl/drivers/stm32f2x/systick/systick.c +++ b/mkrtos_knl/drivers/stm32f2x/systick/systick.c @@ -2,7 +2,7 @@ #include "arch.h" #include "thread.h" #include "ipc.h" - +#include "futex.h" static umword_t sys_tick_cnt; umword_t sys_tick_cnt_get(void) @@ -14,6 +14,7 @@ void SysTick_Handler(void) { // 进行上下文切换 thread_sched(); - timeout_times_tick(); sys_tick_cnt++; + timeout_times_tick(); + futex_timeout_times_tick(); } diff --git a/mkrtos_knl/inc/knl/access.h b/mkrtos_knl/inc/knl/access.h new file mode 100644 index 000000000..5937082a4 --- /dev/null +++ b/mkrtos_knl/inc/knl/access.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +bool_t is_rw_access(void *addr, size_t size, bool_t ignore_null); diff --git a/mkrtos_knl/inc/knl/futex.h b/mkrtos_knl/inc/knl/futex.h index 45dcbb04b..4df4eb6e9 100644 --- a/mkrtos_knl/inc/knl/futex.h +++ b/mkrtos_knl/inc/knl/futex.h @@ -1,3 +1,3 @@ #pragma once - +void futex_timeout_times_tick(void); diff --git a/mkrtos_knl/knl/access.c b/mkrtos_knl/knl/access.c new file mode 100644 index 000000000..c073442b0 --- /dev/null +++ b/mkrtos_knl/knl/access.c @@ -0,0 +1,32 @@ + +#include "types.h" +#include +#include +#include + +/** + * @brief 检测内存是否可访问 + * + * @param addr + * @param size + * @return bool_t + */ +bool_t is_rw_access(void *addr, size_t size, bool_t ignore_null) +{ + if (addr == NULL && ignore_null) + { + return TRUE; + } + + void *mem; + size_t mem_size; + task_t *cur_task = thread_get_current_task(); + + mm_space_get_ram_block(&cur_task->mm_space, &mem, &mem_size); + if (mem >= addr && ((char *)addr + size) < (char *)mem + mem_size) + { + return TRUE; + } + + return FALSE; +} diff --git a/mkrtos_knl/knl/futex.c b/mkrtos_knl/knl/futex.c index a6dbd7586..dc4823dda 100644 --- a/mkrtos_knl/knl/futex.c +++ b/mkrtos_knl/knl/futex.c @@ -1,4 +1,14 @@ - +/** + * @file futex.c + * @author zhangzheng (1358745329@qq.com) + * @brief futex在内核中实现 + * @note TODO: 可以使用hashmap优化 + * @version 0.1 + * @date 2023-11-20 + * + * @copyright Copyright (c) 2023 + * + */ #include "types.h" #include "init.h" #include "prot.h" @@ -13,10 +23,13 @@ #include "globals.h" #include "string.h" #include "ipc.h" +#include "err.h" +#include #define INT_MAX 0x7fffffff #define FT_ADDR_NR 16 //!< 最多加锁的对象 + #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 #define FUTEX_FD 2 @@ -58,6 +71,50 @@ typedef struct futex } futex_t; static futex_t futex_obj; static void futex_init(futex_t *ft); +typedef struct futex_wait_item +{ + slist_head_t node; + thread_t *th; + umword_t sleep_times; +} futex_wait_item_t; +static slist_head_t wait_list; + +/** + * @brief 初始化一个超时等待队列 + * + */ +static void futex_wait_list_init(void) +{ + slist_init(&wait_list); +} +INIT_KOBJ(futex_wait_list_init); +/** + * @brief 检查超时队列 + * + */ +void futex_timeout_times_tick(void) +{ + futex_wait_item_t *item; + + slist_foreach(item, &wait_list, node) //!< 第一次循环等待的ipc + { + if (item->sleep_times > 0) + { + if ((--item->sleep_times) == 0) + { + //!< 超时时间满后直接唤醒等待者 + thread_ready(item->th, TRUE); + } + } + else + { + if (item->th->status == THREAD_SUSPEND) + { + thread_ready(item->th, TRUE); + } + } + } +} static void futex_reg(void) { futex_init(&futex_obj); @@ -130,8 +187,9 @@ static futex_lock_t *futex_find(futex_t *fst, void *uaddr) } return NULL; } + static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t val, - const struct timespec *timeout, uint32_t uaddr2, uint32_t val3, int tid) + umword_t timeout /*val2*/, uint32_t uaddr2, uint32_t val3, int tid) { thread_t *cur_th = thread_get_current(); @@ -143,6 +201,11 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v { case FUTEX_REQUEUE: { + if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE)) + { + spinlock_set(&fst->lock, status); + return -EACCES; + } if (val3 == *uaddr) { futex_lock_t *flt = futex_find(fst, uaddr); @@ -198,6 +261,11 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v break; case FUTEX_WAIT: { + if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE)) + { + spinlock_set(&fst->lock, status); + return -EACCES; + } if (val == *uaddr) { ref_counter_inc(&cur_th->ref); @@ -207,8 +275,33 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v spinlock_set(&fst->lock, status); return -ENOMEM; } - thread_suspend(cur_th); // TODO:考虑超时时间 - preemption(); + if (timeout != 0) + { + //! 加入到等待队列中 + futex_wait_item_t item = { + .th = cur_th, + .sleep_times = timeout, + }; + + slist_init(&item.node); + slist_add_append(&wait_list, &item.node); + thread_suspend(cur_th); + preemption(); + slist_del(&item.node); + if (timeout <= 0) + { + ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj); + spinlock_set(&fst->lock, status); + return -ETIMEDOUT; + } + } + else + { + // 一直等待 + thread_suspend(cur_th); + preemption(); + } + ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj); } else @@ -249,6 +342,11 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v case FUTEX_UNLOCK_PI: case FUTEX_WAKE_CLEAR: { + if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE)) + { + spinlock_set(&fst->lock, status); + return -EACCES; + } futex_lock_t *flt = futex_find(fst, uaddr); int rel_cnt = 0; @@ -277,6 +375,11 @@ static int futex_dispose(futex_t *fst, uint32_t *uaddr, int futex_op, uint32_t v } case FUTEX_LOCK_PI: { + if (!is_rw_access(uaddr, sizeof(*uaddr), FALSE)) + { + spinlock_set(&fst->lock, status); + return -EACCES; + } if (*uaddr = 0) { *uaddr = tid; @@ -320,7 +423,7 @@ static void futex_syscall(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_ta uint32_t *uaddr = (uint32_t *)(msg->msg_buf[0]); int futex_op = msg->msg_buf[1]; uint32_t val = msg->msg_buf[2]; - const struct timespec *timeout = (const struct timespec *)(msg->msg_buf[3]); + umword_t timeout = msg->msg_buf[3]; uint32_t uaddr2 = msg->msg_buf[4]; uint32_t val3 = msg->msg_buf[5]; int tid = msg->msg_buf[6]; @@ -334,16 +437,10 @@ static void futex_syscall(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_ta } static void futex_release_stage1(kobject_t *kobj) { - // futex_t *futex = container_of(kobj, futex_t, kobj); - - // kobject_invalidate(kobj); - /*TODO:唤醒所有挂起的线程*/ + /*TODO:删除task所占用的futex资源*/ } static void futex_release_stage2(kobject_t *kobj) { - // futex_t *ipc = container_of(kobj, futex_t, kobj); - - // mm_limit_free(ipc->lim, kobj); printk("futex don't release.\n"); } static void futex_init(futex_t *ft) @@ -354,29 +451,3 @@ static void futex_init(futex_t *ft) ft->kobj.stage_1_func = futex_release_stage1; ft->kobj.stage_2_func = futex_release_stage2; } -// static futex_t *futex_create(ram_limit_t *lim) -// { -// futex_t *ft = mm_limit_alloc(lim, sizeof(futex_t)); - -// if (!ft) -// { -// return NULL; -// } -// memset(ft, 0, sizeof(futex_t)); -// futex_init(ft, lim); -// return ft; -// } -// static kobject_t *futex_create_func(ram_limit_t *lim, umword_t arg0, umword_t arg1, -// umword_t arg2, umword_t arg3) -// { -// return &futex_create(lim)->kobj; -// } -/** - * @brief 工厂注册函数 - * - */ -// static void futex_factory_register(void) -// { -// factory_register(futex_create_func, FUTEX_PROT); -// } -// INIT_KOBJ(futex_factory_register); diff --git a/mkrtos_knl/knl/ipc.c b/mkrtos_knl/knl/ipc.c index 26ae66e18..bece3f8a9 100755 --- a/mkrtos_knl/knl/ipc.c +++ b/mkrtos_knl/knl/ipc.c @@ -63,7 +63,7 @@ static slist_head_t wait_list; * @brief 初始化一个超时等待队列 * */ -void timeout_wait_list_init(void) +static void timeout_wait_list_init(void) { slist_init(&wait_list); } diff --git a/mkrtos_script/build.sh b/mkrtos_script/build.sh index d87fbefe7..b9d98b338 100755 --- a/mkrtos_script/build.sh +++ b/mkrtos_script/build.sh @@ -1,9 +1,9 @@ #!/bin/bash -# export TOOLCHAIN=/home/zhangzheng/gcc-arm-none-eabi-5_4-2016q3/bin/ -# export TOOLCHAIN_LIB=/home/zhangzheng/gcc-arm-none-eabi-5_4-2016q3/lib/gcc/arm-none-eabi/5.4.1/armv7-m -export TOOLCHAIN=/Users/zhangzheng/gcc-arm-none-eabi-10.3-2021.10/bin/ -export TOOLCHAIN_LIB=/Users/zhangzheng/gcc-arm-none-eabi-10.3-2021.10/lib/gcc/arm-none-eabi/10.3.1/thumb/v7-m/nofp +export TOOLCHAIN=/home/zhangzheng/gcc-arm-none-eabi-5_4-2016q3/bin/ +export TOOLCHAIN_LIB=/home/zhangzheng/gcc-arm-none-eabi-5_4-2016q3/lib/gcc/arm-none-eabi/5.4.1/armv7-m +# export TOOLCHAIN=/Users/zhangzheng/gcc-arm-none-eabi-10.3-2021.10/bin/ +# export TOOLCHAIN_LIB=/Users/zhangzheng/gcc-arm-none-eabi-10.3-2021.10/lib/gcc/arm-none-eabi/10.3.1/thumb/v7-m/nofp export KEN_OFFSET=0x2000 export INIT_OFFSET=0x10000 export BOOTFS_ADDR_OFFSET=0x20000 @@ -12,7 +12,6 @@ export KNL_DATA=0x20000000 export KNL_DATA_SIZE=64K export BOARD=STM32F2x - export PYTHON_EXECUTABLE=python3 set -e diff --git a/mkrtos_tool/kconfig/__pycache__/kconfigfunctions.cpython-38.pyc b/mkrtos_tool/kconfig/__pycache__/kconfigfunctions.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03368ce9fd894be168d4bfaee8d1ae75bab882bc GIT binary patch literal 19172 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 literal 0 HcmV?d00001 diff --git a/mkrtos_tool/kconfig/__pycache__/kconfiglib.cpython-38.pyc b/mkrtos_tool/kconfig/__pycache__/kconfiglib.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e23e594f7d38be6c030b79cc4a88131b06f8593 GIT binary patch literal 159413 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�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

CFi>rq7bxJ8r_s}sBGNMLKi0mH1cGV6zw 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 literal 0 HcmV?d00001 diff --git a/mkrtos_user/lib/libc_backend/src/futex_backend.c b/mkrtos_user/lib/libc_backend/src/futex_backend.c index b315e42cd..a738a83ee 100644 --- a/mkrtos_user/lib/libc_backend/src/futex_backend.c +++ b/mkrtos_user/lib/libc_backend/src/futex_backend.c @@ -30,20 +30,20 @@ int be_futex(uint32_t *uaddr, int futex_op, uint32_t val, struct pthread *pt = __pthread_self(); ipc_timeout_t to = ipc_timeout_create2(0, 0); umword_t total = 0; + umword_t st_val; sys_info_t sys_info; + msg_tag_t tag; if (timeout && !(futex_op & FUTEX_REQUEUE)) { to = ipc_timeout_create2(timeout->tv_sec * 1000 + timeout->tv_nsec / 1000 / 1000, 0); total = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000 / 1000; } - umword_t st_val; _try_again: - sys_read_info(SYS_PROT, &sys_info); st_val = sys_info.sys_tick; - msg_tag_t tag = futex_ctrl(FUTEX_PROT, uaddr, futex_op, val, (void *)timeout, uaddr2, val3, pt->tid); + tag = futex_ctrl(FUTEX_PROT, uaddr, futex_op, val, total, uaddr2, val3, pt->tid); if (msg_tag_get_val(tag) == -EWTIMEDOUT) { umword_t en_val; diff --git a/mkrtos_user/lib/libc_backend/src/sys_backend.c b/mkrtos_user/lib/libc_backend/src/sys_backend.c index 0877dd9bf..b50a12d21 100644 --- a/mkrtos_user/lib/libc_backend/src/sys_backend.c +++ b/mkrtos_user/lib/libc_backend/src/sys_backend.c @@ -42,7 +42,6 @@ int be_clone(int (*func)(void *), void *stack, int flags, void *args, pid_t *pti ph = (struct pthread *)((char *)tls - sizeof(struct pthread)); - th1_hd = handler_alloc(); if (th1_hd == HANDLER_INVALID) { @@ -64,8 +63,9 @@ int be_clone(int (*func)(void *), void *stack, int flags, void *args, pid_t *pti stack = (char *)stack - MSG_BUG_LEN; umword_t *stack_tmp = (umword_t *)stack; + // 设置调用参数等 *(--stack_tmp) = (umword_t)args; - *(--stack_tmp) = (umword_t)0; + *(--stack_tmp) = (umword_t)0; // 保留 *(--stack_tmp) = (umword_t)func; tag = thread_exec_regs(th1_hd, (umword_t)__pthread_new_thread_entry__, (umword_t)stack_tmp, RAM_BASE(), 0); @@ -80,7 +80,10 @@ int be_clone(int (*func)(void *), void *stack, int flags, void *args, pid_t *pti handler_free_umap(th1_hd); return msg_tag_get_prot(tag); } - thread_run(th1_hd, 2); + ph->hd = th1_hd; + ph->ctid = (umword_t)ctid; + *ptid = th1_hd; + thread_run(th1_hd, 2); // 优先级默认为2 return 0; } diff --git a/mkrtos_user/lib/sys/inc/u_futex.h b/mkrtos_user/lib/sys/inc/u_futex.h index 1ed8cbc58..d817f9a6b 100644 --- a/mkrtos_user/lib/sys/inc/u_futex.h +++ b/mkrtos_user/lib/sys/inc/u_futex.h @@ -3,4 +3,4 @@ #include msg_tag_t futex_ctrl(obj_handler_t obj, uint32_t *uaddr, int futex_op, uint32_t val, - void *timeout, uint32_t uaddr2, uint32_t val3, int tid); + umword_t timeout, uint32_t uaddr2, uint32_t val3, int tid); diff --git a/mkrtos_user/lib/sys/src/u_futex.c b/mkrtos_user/lib/sys/src/u_futex.c index 691685271..ad7f25a8b 100644 --- a/mkrtos_user/lib/sys/src/u_futex.c +++ b/mkrtos_user/lib/sys/src/u_futex.c @@ -10,7 +10,7 @@ enum futex_op FUTEX_CTRL, }; msg_tag_t futex_ctrl(obj_handler_t obj, uint32_t *uaddr, int futex_op, uint32_t val, - void *timeout, uint32_t uaddr2, uint32_t val3, int tid) + umword_t timeout, uint32_t uaddr2, uint32_t val3, int tid) { ipc_msg_t *msg; diff --git a/mkrtos_user/server/init/src/test/pthread_lock_test.c b/mkrtos_user/server/init/src/test/pthread_lock_test.c index e08c54bfa..83d9d09ed 100644 --- a/mkrtos_user/server/init/src/test/pthread_lock_test.c +++ b/mkrtos_user/server/init/src/test/pthread_lock_test.c @@ -14,68 +14,53 @@ #include #define DEBUG_IPC_CALL 1 -static umword_t th1_hd = 0; -static umword_t th2_hd = 0; -static umword_t ipc_hd = 0; static pthread_mutex_t lock; +static pthread_t pth; +static pthread_t pth2; -static char msg_buf0[MSG_BUG_LEN]; -static char msg_buf1[MSG_BUG_LEN]; #define STACK_SIZE 2048 static __attribute__((aligned(8))) uint8_t stack0[STACK_SIZE]; static __attribute__((aligned(8))) uint8_t stack1[STACK_SIZE]; static void hard_sleep(void) { - for (volatile int i; i < 10000000; i++) ; } -static void thread_test_func(void) +static void *thread_test_func(void* arg) { - char *buf; - umword_t len; - thread_msg_buf_get(th1_hd, (umword_t *)(&buf), NULL); while (1) { pthread_mutex_lock(&lock); printf("thread 1 ..\n"); pthread_mutex_unlock(&lock); } - printf("thread_test_func.\n"); - task_unmap(TASK_PROT, vpage_create_raw3(KOBJ_DELETE_RIGHT, 0, th1_hd)); - printf("Error\n"); + return NULL; } -static void thread_test_func2(void) +static void *thread_test_func2(void* arg) { - char *buf; - umword_t len; - thread_msg_buf_get(th2_hd, (umword_t *)(&buf), NULL); while (1) { pthread_mutex_lock(&lock); printf("thread 2 ..\n"); pthread_mutex_unlock(&lock); } - printf("thread_test_func2.\n"); - task_unmap(TASK_PROT, vpage_create_raw3(KOBJ_DELETE_RIGHT, 0, th2_hd)); - printf("Error\n"); -} -static pthread_t pth; -static void *func_test(void *arg) -{ return NULL; } + /** * */ void pthread_lock_test(void) { - pthread_mutex_init(&lock, NULL); pthread_attr_t attr; + + pthread_mutex_init(&lock, NULL); pthread_attr_init(&attr); pthread_attr_setstack(&attr, stack0, STACK_SIZE); - pthread_create(&pth, &attr, func_test, NULL); + pthread_create(&pth, &attr, thread_test_func, NULL); + pthread_attr_setstack(&attr, stack1, STACK_SIZE); + pthread_create(&pth2, &attr, thread_test_func2, NULL); // th1_hd = handler_alloc(); // assert(th1_hd != HANDLER_INVALID);