mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 03:41:55 +00:00
Support MIPS 64bits for loongson 3A4000/3B3000. v5.0.34
This commit is contained in:
parent
aba6667357
commit
1589858cb0
16 changed files with 543 additions and 185 deletions
3
trunk/3rdparty/st-srs/README.md
vendored
3
trunk/3rdparty/st-srs/README.md
vendored
|
@ -35,6 +35,8 @@ For Linux aarch64, which fail with `Unknown CPU architecture`:
|
|||
make linux-debug EXTRA_CFLAGS="-D__aarch64__"
|
||||
```
|
||||
|
||||
> Note: For more CPU architectures, please see [#22](https://github.com/ossrs/state-threads/issues/22)
|
||||
|
||||
Linux with valgrind:
|
||||
|
||||
```bash
|
||||
|
@ -110,6 +112,7 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche
|
|||
- [x] LOONGARCH: Support loongarch for loongson CPU, [#24](https://github.com/ossrs/state-threads/issues/24).
|
||||
- [x] System: Support Multiple Threads for Linux and Darwin. [#19](https://github.com/ossrs/state-threads/issues/19), [srs#2188](https://github.com/ossrs/srs/issues/2188).
|
||||
- [x] RISCV: Support RISCV for RISCV CPU, [#24](https://github.com/ossrs/state-threads/pull/28).
|
||||
- [x] MIPS: Support Linux/MIPS64 for loongson 3A4000/3B3000, [#21](https://github.com/ossrs/state-threads/pull/21).
|
||||
- [ ] IDE: Support CLion for debugging and learning.
|
||||
- [ ] System: Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12).
|
||||
|
||||
|
|
64
trunk/3rdparty/st-srs/auto/codecov.sh
vendored
64
trunk/3rdparty/st-srs/auto/codecov.sh
vendored
|
@ -1,52 +1,38 @@
|
|||
#!/bin/bash
|
||||
|
||||
# In .circleci/config.yml, generate *.gcno with
|
||||
# ./configure --gcov --without-research --without-librtmp && make
|
||||
# and generate *.gcda by
|
||||
# ./objs/srs_utest
|
||||
|
||||
# Workdir is objs/cover.
|
||||
workdir=`pwd`/codecov && rm -rf $workdir
|
||||
|
||||
# Tool git is required to map the right path.
|
||||
git --version >/dev/null 2>&1
|
||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "Tool git is required, ret=$ret"; exit $ret; fi
|
||||
# Workdir is obj/coverage.
|
||||
workdir=`pwd`/coverage
|
||||
|
||||
# Create trunk under workdir.
|
||||
mkdir -p $workdir && cd $workdir
|
||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "Enter workdir failed, ret=$ret"; exit $ret; fi
|
||||
|
||||
# Collect all *.gcno and *.gcda to objs/cover.
|
||||
cd $workdir && for file in $(cd .. && ls *.c); do
|
||||
cp ../$file $file && echo "Copy $file" &&
|
||||
if [[ -f ../obj/${file%.*}.gcno ]]; then
|
||||
cp ../obj/${file%.*}.* .
|
||||
fi
|
||||
done
|
||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect *.gcno and *.gcda failed, ret=$ret"; exit $ret; fi
|
||||
|
||||
# Generate *.gcov for coverage.
|
||||
cd $workdir &&
|
||||
for file in $(ls *.c); do
|
||||
gcov $file -o `dirname $file`
|
||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect $file failed, ret=$ret"; exit $ret; fi
|
||||
done
|
||||
|
||||
# Filter the gcov files, remove utest or gtest.
|
||||
cd $workdir &&
|
||||
rm -f *gtest*.gcov *utest*.gcov
|
||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "Cook gcov files failed, ret=$ret"; exit $ret; fi
|
||||
CODECOV_ARGS=""
|
||||
if [[ $ST_PROJECT != '' ]]; then
|
||||
# -R root dir Used when not in git/hg project to identify project root directory
|
||||
# -p dir Project root directory. Also used when preparing gcov
|
||||
CODECOV_ARGS="$CODECOV_ARGS -R $ST_PROJECT -p $ST_PROJECT"
|
||||
fi
|
||||
if [[ $ST_BRANCH != '' ]]; then
|
||||
# -B branch Specify the branch name
|
||||
CODECOV_ARGS="$CODECOV_ARGS -B $ST_BRANCH"
|
||||
fi
|
||||
if [[ $ST_SHA != '' ]]; then
|
||||
# -C sha Specify the commit sha
|
||||
CODECOV_ARGS="$CODECOV_ARGS -C $ST_SHA"
|
||||
fi
|
||||
if [[ $ST_PR != '' ]]; then
|
||||
# -P pr Specify the pull request number
|
||||
CODECOV_ARGS="$CODECOV_ARGS -P $ST_PR"
|
||||
fi
|
||||
|
||||
# Upload report with *.gcov
|
||||
# Remark: The file codecov.yml is not neccessary. It literally depends on git.
|
||||
# Note: The right path is like:
|
||||
# https://codecov.io/gh/ossrs/srs/src/3.0release/trunk/src/protocol/srs_rtmp_stack.cpp
|
||||
# https://codecov.io/gh/ossrs/srs/src/20fbb4466fdc8ba5d810b8570df6004063212838/trunk/src/protocol/srs_rtmp_stack.cpp
|
||||
# Remark: It takes a few minutes to sync with github, so it might not available when CircleCI is done.
|
||||
# https://circleci.com/gh/ossrs/srs/tree/3.0release
|
||||
#
|
||||
# Note: Use '-X gcov' to avoid generate the gcov files again.
|
||||
# https://app.codecov.io/gh/ossrs/state-threads/blob/srs/sched.c
|
||||
# https://app.codecov.io/gh/ossrs/state-threads/blob/593cf748f055ca383867003e409a423efd8f8f86/sched.c
|
||||
cd $workdir &&
|
||||
export CODECOV_TOKEN="0d616496-f781-4e7c-b285-d1f70a1cdf24" &&
|
||||
bash <(curl -s https://codecov.io/bash) -X gcov &&
|
||||
export CODECOV_TOKEN="$CODECOV_TOKEN" &&
|
||||
bash <(curl -s https://codecov.io/bash) $CODECOV_ARGS -f '!*gtest*' -f '!*c++*' &&
|
||||
echo "Done" && exit 0
|
||||
|
||||
|
|
20
trunk/3rdparty/st-srs/auto/coverage.sh
vendored
20
trunk/3rdparty/st-srs/auto/coverage.sh
vendored
|
@ -1,23 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [[ ! -f utest/gtest/include/gtest/gtest.h ]]; then
|
||||
(
|
||||
cd utest && rm -rf gtest &&
|
||||
curl https://github.com/google/googletest/archive/release-1.6.0.tar.gz -L -o googletest-release-1.6.0.tar.gz &&
|
||||
tar xf googletest-release-1.6.0.tar.gz &&
|
||||
ln -sf googletest-release-1.6.0 gtest &&
|
||||
echo "Setup gtest ok"
|
||||
)
|
||||
fi
|
||||
if [[ ! -f utest/gtest/include/gtest/gtest.h ]]; then
|
||||
echo "No utest/gtest, please download from https://github.com/google/googletest/releases/tag/release-1.6.0"
|
||||
if [[ ! -f utest/gtest-fit/googletest/include/gtest/gtest.h ]]; then
|
||||
echo "No utest/gtest, please download from https://github.com/google/googletest/releases/tag/release-1.11.0"
|
||||
exit -1
|
||||
else
|
||||
echo "Check utest/gtest ok"
|
||||
fi
|
||||
|
||||
if [[ $(gcovr --version >/dev/null && echo yes) != yes ]]; then
|
||||
echo "Please install gcovr: https://github.com/ossrs/state-threads/tree/srs#utest-and-coverage"
|
||||
echo "Please install gcovr"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
|
@ -34,6 +25,9 @@ fi
|
|||
|
||||
echo "Generating coverage"
|
||||
mkdir -p coverage &&
|
||||
gcovr -r . -e LINUX -e DARWIN -e examples --html --html-details -o coverage/st.html &&
|
||||
(cd obj && rm -f gtest-all.gcda gtest-all.gcno) &&
|
||||
(cd obj && rm -f *.c *.cpp gtest-fit && ln -sf ../*.c . && ln -sf ../utest/*.cpp && ln -sf ../utest/gtest-fit .) &&
|
||||
(cd obj && gcovr --gcov-exclude gtest --html --html-details -o ../coverage/st.html) &&
|
||||
(cd obj && rm -f *.c *.cpp gtest-fit) &&
|
||||
echo "Coverage report at coverage/st.html" &&
|
||||
open coverage/st.html
|
||||
|
|
15
trunk/3rdparty/st-srs/auto/fast.sh
vendored
15
trunk/3rdparty/st-srs/auto/fast.sh
vendored
|
@ -22,19 +22,12 @@ ret=$?; if [[ 0 -ne $ret ]]; then echo "Make ST utest fail, ret=$ret"; exit $ret
|
|||
|
||||
echo "Generating coverage"
|
||||
mkdir -p coverage &&
|
||||
gcovr -r . -e LINUX -e DARWIN -e examples --html --html-details -o coverage/st.html &&
|
||||
(cd obj && rm -f gtest-all.gcda gtest-all.gcno) &&
|
||||
(cd obj && rm -f *.c *.cpp gtest-fit && ln -sf ../*.c . && ln -sf ../utest/*.cpp && ln -sf ../utest/gtest-fit .) &&
|
||||
(cd obj && gcovr --gcov-exclude gtest --html --html-details -o ../coverage/st.html) &&
|
||||
(cd obj && rm -f *.c *.cpp gtest-fit) &&
|
||||
echo "Coverage report at coverage/st.html" &&
|
||||
open coverage/st.html
|
||||
|
||||
popd
|
||||
echo "UTest done, restore $(pwd)"
|
||||
|
||||
cat << END > /dev/stdout
|
||||
|
||||
# CLI For DARWIN
|
||||
cd $PWD && rm -f ./obj/*.gcda &&
|
||||
make darwin-debug-gcov && ./obj/st_utest &&
|
||||
mkdir -p coverage && gcovr -r . -e LINUX -e DARWIN -e examples --html --html-details -o coverage/st.html &&
|
||||
open coverage/st.html
|
||||
|
||||
END
|
6
trunk/3rdparty/st-srs/md.h
vendored
6
trunk/3rdparty/st-srs/md.h
vendored
|
@ -182,6 +182,10 @@
|
|||
#error "ARM/Linux pre-glibc2 not supported yet"
|
||||
#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
|
||||
|
||||
#elif defined(__mips64)
|
||||
/* https://github.com/ossrs/state-threads/issues/21 */
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
#define MD_GET_SP(_t) *((long *)&((_t)->context[0].__jmpbuf[0]))
|
||||
#elif defined(__mips__)
|
||||
/* https://github.com/ossrs/state-threads/issues/21 */
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
|
@ -191,7 +195,7 @@
|
|||
#define MD_USE_BUILTIN_SETJMP
|
||||
#define MD_GET_SP(_t) *((long *)&((_t)->context[0].__jmpbuf[0]))
|
||||
|
||||
#elif defined(__loongarch__)
|
||||
#elif defined(__loongarch64)
|
||||
/* https://github.com/ossrs/state-threads/issues/24 */
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
#define MD_GET_SP(_t) *((long *)&((_t)->context[0].__jmpbuf[0]))
|
||||
|
|
80
trunk/3rdparty/st-srs/md_linux.S
vendored
80
trunk/3rdparty/st-srs/md_linux.S
vendored
|
@ -433,9 +433,87 @@
|
|||
|
||||
|
||||
|
||||
#elif defined(__mips64)
|
||||
|
||||
/****************************************************************/
|
||||
/* For MIPS64, see https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MIPS_Architecture_MIPS64_InstructionSet_%20AFP_P_MD00087_06.05.pdf */
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
*/
|
||||
#define JB_SP 0 /* Stack pointer */
|
||||
#define JB_RA 11 /* Return address */
|
||||
#define JB_GP 1 /* Global pointer */
|
||||
#define JB_S0 3 /* S0-S7, Saved temporaries */
|
||||
#define JB_S1 4 /* S0-S7, Saved temporaries */
|
||||
#define JB_S2 5 /* S0-S7, Saved temporaries */
|
||||
#define JB_S3 6 /* S0-S7, Saved temporaries */
|
||||
#define JB_S4 7 /* S0-S7, Saved temporaries */
|
||||
#define JB_S5 8 /* S0-S7, Saved temporaries */
|
||||
#define JB_S6 9 /* S0-S7, Saved temporaries */
|
||||
#define JB_S7 10 /* S0-S7, Saved temporaries */
|
||||
#define JB_FP 2 /* FP/S8 Frame pointer */
|
||||
|
||||
.file "md_linux.S"
|
||||
.text
|
||||
|
||||
/* _st_md_cxt_save(__jmp_buf env) */ /* The env is $a0, https://en.wikipedia.org/wiki/MIPS_architecture#Calling_conventions */
|
||||
.globl _st_md_cxt_save
|
||||
.type _st_md_cxt_save, %function
|
||||
.align 2
|
||||
_st_md_cxt_save:
|
||||
sd $sp, 0($a0) /* Save sp to env[0], *(long*)($a0+ 0) =sp */
|
||||
sd $ra, 8($a0) /* Save ra to env[1], *(long*)($a0+ 8)=ra, the return address, https://chortle.ccsu.edu/AssemblyTutorial/Chapter-26/ass26_4.html */
|
||||
sd $gp, 16($a0) /* Save gp to env[2], *(long*)($a0+16) =gp */
|
||||
sd $s0, 24($a0) /* Save s0 to env[3], *(long*)($a0+24)=s0 */
|
||||
sd $s1, 32($a0) /* Save s1 to env[4], *(long*)($a0+32)=s1 */
|
||||
sd $s2, 40($a0) /* Save s2 to env[5], *(long*)($a0+40)=s2 */
|
||||
sd $s3, 48($a0) /* Save s3 to env[6], *(long*)($a0+48)=s3 */
|
||||
sd $s4, 56($a0) /* Save s4 to env[7], *(long*)($a0+56)=s4 */
|
||||
sd $s5, 64($a0) /* Save s5 to env[8], *(long*)($a0+64)=s5 */
|
||||
sd $s6, 72($a0) /* Save s6 to env[9], *(long*)($a0+72)=s6 */
|
||||
sd $s7, 80($a0) /* Save s7 to env[10], *(long*)($a0+80)=s7 */
|
||||
sd $fp, 88($a0) /* Save fp to env[11], *(long*)($a0+88) =fp */
|
||||
li $v0, 0 /* Set return value to 0 */
|
||||
jr $ra /* Return */
|
||||
|
||||
.size _st_md_cxt_save, .-_st_md_cxt_save
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* _st_md_cxt_restore(__jmp_buf env, int val) */
|
||||
.globl _st_md_cxt_restore
|
||||
.type _st_md_cxt_restore, %function
|
||||
.align 2
|
||||
_st_md_cxt_restore:
|
||||
ld $sp, 0($a0) /* Load sp from env[0], sp=*(long*)($a0+ 0) */
|
||||
ld $ra, 8($a0) /* Load sp from env[1], ra=*(long*)($a0+ 8), the saved return address */
|
||||
ld $gp, 16($a0) /* Load sp from env[2], gp=*(long*)($a0+16) */
|
||||
ld $s0, 24($a0) /* Load sp from env[3], s0=*(long*)($a0+24) */
|
||||
ld $s1, 32($a0) /* Load sp from env[4], s1=*(long*)($a0+32) */
|
||||
ld $s2, 40($a0) /* Load sp from env[5], s2=*(long*)($a0+40) */
|
||||
ld $s3, 48($a0) /* Load sp from env[6], s3=*(long*)($a0+48) */
|
||||
ld $s4, 56($a0) /* Load sp from env[7], s4=*(long*)($a0+56) */
|
||||
ld $s5, 64($a0) /* Load sp from env[8], s5=*(long*)($a0+64) */
|
||||
ld $s6, 72($a0) /* Load sp from env[9], s6=*(long*)($a0+72) */
|
||||
ld $s7, 80($a0) /* Load sp from env[10], s7=*(long*)($a0+80) */
|
||||
ld $fp, 88($a0) /* Load sp from env[2], fp=*(long*)($a0+88) */
|
||||
li $v0, 1 /* Set return value to 1 */
|
||||
jr $ra /* Return to the saved return address */
|
||||
|
||||
.size _st_md_cxt_restore, .-_st_md_cxt_restore
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
/****************************************************************/
|
||||
/* For MIPS32, see https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00565-2B-MIPS32-QRC-01.01.pdf */
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
|
@ -513,7 +591,7 @@
|
|||
|
||||
|
||||
|
||||
#elif defined(__loongarch__)
|
||||
#elif defined(__loongarch64)
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ int main(int argc, char** argv)
|
|||
{
|
||||
st_init();
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
int i;
|
||||
for (i = 0; i < 10000; i++) {
|
||||
printf("#%03d, Hello, state-threads world!\n", i);
|
||||
st_sleep(1);
|
||||
}
|
||||
|
|
68
trunk/3rdparty/st-srs/tools/porting/porting.c
vendored
68
trunk/3rdparty/st-srs/tools/porting/porting.c
vendored
|
@ -25,11 +25,23 @@ int main(int argc, char** argv)
|
|||
// https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00565-2B-MIPS32-QRC-01.01.pdf
|
||||
printf("__mips__: %d, __mips: %d, _MIPSEL: %d\n", __mips__, __mips, _MIPSEL);
|
||||
#endif
|
||||
#ifdef __mips64
|
||||
printf("__mips64: %d\n", __mips64);
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
printf("__x86_64__: %d\n", __x86_64__);
|
||||
#endif
|
||||
#ifdef __loongarch__
|
||||
printf("__loongarch__: %d, __loongarch64 :%d\n", __loongarch__, __loongarch64);
|
||||
#ifdef __loongarch64
|
||||
printf("__loongarch__: %d __loongarch64: %d\n", __loongarch__, __loongarch64);
|
||||
#endif
|
||||
#ifdef __riscv
|
||||
printf("__riscv: %d\n", __riscv);
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
printf("__arm__: %d\n", __arm__);
|
||||
#endif
|
||||
#ifdef __aarch64__
|
||||
printf("__aarch64__: %d\n", __aarch64__);
|
||||
#endif
|
||||
|
||||
printf("\nCompiler specs:\n");
|
||||
|
@ -71,7 +83,52 @@ int foo_return_one_arg1(int r0)
|
|||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef __mips__
|
||||
|
||||
#if defined(__riscv) || defined(__arm__) || defined(__aarch64__)
|
||||
void print_jmpbuf() {
|
||||
}
|
||||
#elif __mips64
|
||||
void print_jmpbuf()
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/MIPS_architecture#Calling_conventions
|
||||
register void* ra asm("ra");
|
||||
register void* gp asm("gp");
|
||||
register void* sp asm("sp");
|
||||
register void* fp asm("fp");
|
||||
// $s0–$s7 $16–$23 saved temporaries
|
||||
register void* s0 asm("s0");
|
||||
register void* s1 asm("s1");
|
||||
register void* s2 asm("s2");
|
||||
register void* s3 asm("s3");
|
||||
register void* s4 asm("s4");
|
||||
register void* s5 asm("s5");
|
||||
register void* s6 asm("s6");
|
||||
register void* s7 asm("s7");
|
||||
|
||||
/*
|
||||
typedef unsigned long long __jmp_buf[13];
|
||||
typedef struct __jmp_buf_tag {
|
||||
__jmp_buf __jmpbuf;
|
||||
int __mask_was_saved;
|
||||
__sigset_t __saved_mask;
|
||||
} jmp_buf[1];
|
||||
*/
|
||||
jmp_buf ctx = {0};
|
||||
int r0 = setjmp(ctx);
|
||||
if (!r0) {
|
||||
longjmp(ctx, 1);
|
||||
}
|
||||
|
||||
printf("ra=%p, sp=%p, s0=%p, s1=%p, s2=%p, s3=%p, s4=%p, s5=%p, s6=%p, s7=%p, fp=%p, gp=%p\n",
|
||||
ra, sp, s0, s1, s2, s3, s4, s5, s6, s7, fp, gp);
|
||||
|
||||
int nn_jb = sizeof(ctx[0].__jmpbuf);
|
||||
printf("sizeof(jmp_buf)=%d (unsigned long long [%d])\n", nn_jb, nn_jb/8);
|
||||
|
||||
unsigned char* p = (unsigned char*)ctx[0].__jmpbuf;
|
||||
print_buf(p, nn_jb);
|
||||
}
|
||||
#elif __mips__
|
||||
void print_jmpbuf()
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/MIPS_architecture#Calling_conventions
|
||||
|
@ -112,7 +169,7 @@ void print_jmpbuf()
|
|||
unsigned char* p = (unsigned char*)ctx[0].__jb;
|
||||
print_buf(p, nn_jb);
|
||||
}
|
||||
#elif __loongarch__
|
||||
#elif __loongarch64
|
||||
void print_jmpbuf()
|
||||
{
|
||||
// https://github.com/ossrs/state-threads/issues/24#porting
|
||||
|
@ -192,7 +249,8 @@ void print_buf(unsigned char* p, int nn_jb)
|
|||
{
|
||||
printf(" ");
|
||||
|
||||
for (int i = 0; i < nn_jb; i++) {
|
||||
int i;
|
||||
for (i = 0; i < nn_jb; i++) {
|
||||
printf("0x%02x ", (unsigned char)p[i]);
|
||||
|
||||
int newline = ((i + 1) % sizeof(void*));
|
||||
|
|
2
trunk/3rdparty/st-srs/tools/verify/verify.c
vendored
2
trunk/3rdparty/st-srs/tools/verify/verify.c
vendored
|
@ -48,7 +48,7 @@ void verify_jmpbuf()
|
|||
unsigned char* p = (unsigned char*)ctx[0].__jb;
|
||||
print_buf(p, nn_jb);
|
||||
}
|
||||
#elif __loongarch__
|
||||
#elif __loongarch64
|
||||
void verify_jmpbuf()
|
||||
{
|
||||
// https://github.com/ossrs/state-threads/issues/24#porting
|
||||
|
|
25
trunk/3rdparty/st-srs/utest/Makefile
vendored
25
trunk/3rdparty/st-srs/utest/Makefile
vendored
|
@ -4,7 +4,7 @@ ST_DIR = ..
|
|||
# The main dir of st utest.
|
||||
ST_UTEST = .
|
||||
# The main dir of gtest.
|
||||
GTEST_DIR = $(ST_UTEST)/gtest
|
||||
GTEST_DIR = $(ST_UTEST)/gtest-fit/googletest
|
||||
|
||||
# Flags passed to the C++ compiler.
|
||||
CXXFLAGS += -g -O0 -std=c++11
|
||||
|
@ -45,16 +45,29 @@ $(ST_DIR)/obj/gtest.a : $(ST_DIR)/obj/gtest-all.o
|
|||
ST_UTEST_DEPS = $(ST_DIR)/obj/libst.a
|
||||
|
||||
# Depends, utest header files
|
||||
UTEST_DEPS = $(ST_UTEST)/st_utest.hpp
|
||||
UTEST_DEPS = $(ST_UTEST)/st_utest.hpp Makefile
|
||||
|
||||
# Compile all sources files at current directory. For example:
|
||||
# (st_utest.cpp st_utest_coroutines.cpp st_utest_tcp.cpp)
|
||||
SOURCE_FILES = $(shell ls *.cpp)
|
||||
#
|
||||
# Convert all source files to object files. For example:
|
||||
# (st_utest.o st_utest_coroutines.o st_utest_tcp.o)
|
||||
# https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_8.html
|
||||
OBJECTS_FILES = $(patsubst %.cpp,%.o,$(SOURCE_FILES))
|
||||
#
|
||||
# Prefix object files to objects. For example:
|
||||
# ($(ST_DIR)/obj/st_utest.o $(ST_DIR)/obj/st_utest_coroutines.o $(ST_DIR)/obj/st_utest_tcp.o)
|
||||
OBJECTS = $(addprefix $(ST_DIR)/obj/,$(OBJECTS_FILES))
|
||||
|
||||
# Objects, build each object of utest
|
||||
$(ST_DIR)/obj/st_utest.o : st_utest.cpp $(ST_UTEST_DEPS) $(UTEST_DEPS)
|
||||
$(CXX) -c st_utest.cpp -o $@ \
|
||||
$(ST_DIR)/obj/%.o : %.cpp $(ST_UTEST_DEPS) $(UTEST_DEPS)
|
||||
$(CXX) -c $< -o $@ \
|
||||
$(CXXFLAGS) $(UTEST_FLAGS) \
|
||||
$(WARNFLAGS) \
|
||||
-I$(GTEST_DIR)/include -I$(ST_UTEST) -I$(ST_DIR) -I$(ST_DIR)/obj
|
||||
|
||||
# generate the utest binary
|
||||
$(ST_DIR)/obj/st_utest : $(ST_DIR)/obj/st_utest.o $(ST_DIR)/obj/gtest.a $(ST_UTEST_DEPS)
|
||||
# Generate the utest binary
|
||||
$(ST_DIR)/obj/st_utest : $(OBJECTS) $(ST_DIR)/obj/gtest.a $(ST_UTEST_DEPS)
|
||||
$(CXX) -o $@ $(CXXFLAGS) $(UTEST_FLAGS) \
|
||||
-lpthread -ldl $^
|
||||
|
|
114
trunk/3rdparty/st-srs/utest/st_utest.cpp
vendored
114
trunk/3rdparty/st-srs/utest/st_utest.cpp
vendored
|
@ -6,6 +6,14 @@
|
|||
#include <st.h>
|
||||
#include <assert.h>
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const ErrorObject* err) {
|
||||
if (!err) return out;
|
||||
if (err->r0_) out << "r0=" << err->r0_;
|
||||
if (err->errno_) out << ", errno=" << err->errno_;
|
||||
if (!err->message_.empty()) out << ", msg=" << err->message_;
|
||||
return out;
|
||||
}
|
||||
|
||||
// We could do something in the main of utest.
|
||||
// Copy from gtest-1.6.0/src/gtest_main.cc
|
||||
GTEST_API_ int main(int argc, char **argv) {
|
||||
|
@ -25,7 +33,7 @@ GTEST_API_ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
// basic test and samples.
|
||||
VOID TEST(SampleTest, FastSampleInt64Test)
|
||||
VOID TEST(SampleTest, ExampleIntSizeTest)
|
||||
{
|
||||
EXPECT_EQ(1, (int)sizeof(int8_t));
|
||||
EXPECT_EQ(2, (int)sizeof(int16_t));
|
||||
|
@ -33,107 +41,3 @@ VOID TEST(SampleTest, FastSampleInt64Test)
|
|||
EXPECT_EQ(8, (int)sizeof(int64_t));
|
||||
}
|
||||
|
||||
void* pfn_coroutine(void* /*arg*/)
|
||||
{
|
||||
st_usleep(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID TEST(SampleTest, StartCoroutine)
|
||||
{
|
||||
st_thread_t trd = st_thread_create(pfn_coroutine, NULL, 1, 0);
|
||||
EXPECT_TRUE(trd != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd, NULL);
|
||||
}
|
||||
|
||||
VOID TEST(SampleTest, StartCoroutineX3)
|
||||
{
|
||||
st_thread_t trd0 = st_thread_create(pfn_coroutine, NULL, 1, 0);
|
||||
st_thread_t trd1 = st_thread_create(pfn_coroutine, NULL, 1, 0);
|
||||
st_thread_t trd2 = st_thread_create(pfn_coroutine, NULL, 1, 0);
|
||||
EXPECT_TRUE(trd0 != NULL && trd1 != NULL && trd2 != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd1, NULL);
|
||||
st_thread_join(trd2, NULL);
|
||||
st_thread_join(trd0, NULL);
|
||||
}
|
||||
|
||||
void* pfn_coroutine_add(void* arg)
|
||||
{
|
||||
int v = 0;
|
||||
int* pi = (int*)arg;
|
||||
|
||||
// Load the change of arg.
|
||||
while (v != *pi) {
|
||||
v = *pi;
|
||||
st_usleep(0);
|
||||
}
|
||||
|
||||
// Add with const.
|
||||
v += 100;
|
||||
*pi = v;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID TEST(SampleTest, StartCoroutineAdd)
|
||||
{
|
||||
int v = 0;
|
||||
st_thread_t trd = st_thread_create(pfn_coroutine_add, &v, 1, 0);
|
||||
EXPECT_TRUE(trd != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd, NULL);
|
||||
|
||||
EXPECT_EQ(100, v);
|
||||
}
|
||||
|
||||
VOID TEST(SampleTest, StartCoroutineAddX3)
|
||||
{
|
||||
int v = 0;
|
||||
st_thread_t trd0 = st_thread_create(pfn_coroutine_add, &v, 1, 0);
|
||||
st_thread_t trd1 = st_thread_create(pfn_coroutine_add, &v, 1, 0);
|
||||
st_thread_t trd2 = st_thread_create(pfn_coroutine_add, &v, 1, 0);
|
||||
EXPECT_TRUE(trd0 != NULL && trd1 != NULL && trd2 != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd0, NULL);
|
||||
st_thread_join(trd1, NULL);
|
||||
st_thread_join(trd2, NULL);
|
||||
|
||||
EXPECT_EQ(300, v);
|
||||
}
|
||||
|
||||
int pfn_coroutine_params_x4(int a, int b, int c, int d)
|
||||
{
|
||||
int e = 0;
|
||||
|
||||
st_usleep(0);
|
||||
|
||||
e += a + b + c + d;
|
||||
e += 100;
|
||||
return e;
|
||||
}
|
||||
|
||||
void* pfn_coroutine_params(void* arg)
|
||||
{
|
||||
int r0 = pfn_coroutine_params_x4(1, 2, 3, 4);
|
||||
*(int*)arg = r0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID TEST(SampleTest, StartCoroutineParams)
|
||||
{
|
||||
int r0 = 0;
|
||||
st_thread_t trd = st_thread_create(pfn_coroutine_params, &r0, 1, 0);
|
||||
EXPECT_TRUE(trd != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd, NULL);
|
||||
|
||||
EXPECT_EQ(110, r0);
|
||||
}
|
||||
|
||||
|
|
111
trunk/3rdparty/st-srs/utest/st_utest.hpp
vendored
111
trunk/3rdparty/st-srs/utest/st_utest.hpp
vendored
|
@ -10,7 +10,118 @@
|
|||
// @see https://stackoverflow.com/questions/47839718/sstream-redeclared-with-public-access-compiler-error
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <st.h>
|
||||
#include <string>
|
||||
|
||||
#define VOID
|
||||
|
||||
// Close the fd automatically.
|
||||
#define StFdCleanup(fd, stfd) impl__StFdCleanup _ST_free_##fd(&fd, &stfd)
|
||||
#define StStfdCleanup(stfd) impl__StFdCleanup _ST_free_##stfd(NULL, &stfd)
|
||||
class impl__StFdCleanup {
|
||||
int* fd_;
|
||||
st_netfd_t* stfd_;
|
||||
public:
|
||||
impl__StFdCleanup(int* fd, st_netfd_t* stfd) : fd_(fd), stfd_(stfd) {
|
||||
}
|
||||
virtual ~impl__StFdCleanup() {
|
||||
if (stfd_ && *stfd_) {
|
||||
st_netfd_close(*stfd_);
|
||||
} else if (fd_ && *fd_ > 0) {
|
||||
::close(*fd_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For coroutine function to return with error object.
|
||||
struct ErrorObject {
|
||||
int r0_;
|
||||
int errno_;
|
||||
std::string message_;
|
||||
|
||||
ErrorObject(int r0, std::string message) : r0_(r0), errno_(errno), message_(message) {
|
||||
}
|
||||
};
|
||||
extern std::ostream& operator<<(std::ostream& out, const ErrorObject* err);
|
||||
#define ST_ASSERT_ERROR(error, r0, message) if (error) return new ErrorObject(r0, message)
|
||||
#define ST_COROUTINE_JOIN(trd, r0) ErrorObject* r0 = NULL; SrsAutoFree(ErrorObject, r0); if (trd) st_thread_join(trd, (void**)&r0)
|
||||
#define ST_EXPECT_SUCCESS(r0) EXPECT_TRUE(!r0) << r0
|
||||
#define ST_EXPECT_FAILED(r0) EXPECT_TRUE(r0) << r0
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// To free the instance in the current scope, for instance, MyClass* ptr,
|
||||
// which is a ptr and this class will:
|
||||
// 1. free the ptr.
|
||||
// 2. set ptr to NULL.
|
||||
//
|
||||
// Usage:
|
||||
// MyClass* po = new MyClass();
|
||||
// // ...... use po
|
||||
// SrsAutoFree(MyClass, po);
|
||||
//
|
||||
// Usage for array:
|
||||
// MyClass** pa = new MyClass*[size];
|
||||
// // ....... use pa
|
||||
// SrsAutoFreeA(MyClass*, pa);
|
||||
//
|
||||
// @remark the MyClass can be basic type, for instance, SrsAutoFreeA(char, pstr),
|
||||
// where the char* pstr = new char[size].
|
||||
// To delete object.
|
||||
#define SrsAutoFree(className, instance) \
|
||||
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, NULL)
|
||||
// To delete array.
|
||||
#define SrsAutoFreeA(className, instance) \
|
||||
impl_SrsAutoFree<className> _auto_free_array_##instance(&instance, true, false, NULL)
|
||||
// Use free instead of delete.
|
||||
#define SrsAutoFreeF(className, instance) \
|
||||
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, true, NULL)
|
||||
// Use hook instead of delete.
|
||||
#define SrsAutoFreeH(className, instance, hook) \
|
||||
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, hook)
|
||||
// The template implementation.
|
||||
template<class T>
|
||||
class impl_SrsAutoFree
|
||||
{
|
||||
private:
|
||||
T** ptr;
|
||||
bool is_array;
|
||||
bool _use_free;
|
||||
void (*_hook)(T*);
|
||||
public:
|
||||
// If use_free, use free(void*) to release the p.
|
||||
// If specified hook, use hook(p) to release it.
|
||||
// Use delete to release p, or delete[] if p is an array.
|
||||
impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) {
|
||||
ptr = p;
|
||||
is_array = array;
|
||||
_use_free = use_free;
|
||||
_hook = hook;
|
||||
}
|
||||
|
||||
virtual ~impl_SrsAutoFree() {
|
||||
if (ptr == NULL || *ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_use_free) {
|
||||
free(*ptr);
|
||||
} else if (_hook) {
|
||||
_hook(*ptr);
|
||||
} else {
|
||||
if (is_array) {
|
||||
delete[] *ptr;
|
||||
} else {
|
||||
delete *ptr;
|
||||
}
|
||||
}
|
||||
|
||||
*ptr = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// The time unit in ms, for example 100 * SRS_UTIME_MILLISECONDS means 100ms.
|
||||
#define SRS_UTIME_MILLISECONDS 1000
|
||||
|
||||
#endif
|
||||
|
||||
|
|
120
trunk/3rdparty/st-srs/utest/st_utest_coroutines.cpp
vendored
Normal file
120
trunk/3rdparty/st-srs/utest/st_utest_coroutines.cpp
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/* Copyright (c) 2021 Winlin */
|
||||
|
||||
#include <st_utest.hpp>
|
||||
|
||||
#include <st.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// The utest for empty coroutine.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void* coroutine(void* /*arg*/)
|
||||
{
|
||||
st_usleep(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID TEST(CoroutineTest, StartCoroutine)
|
||||
{
|
||||
st_thread_t trd = st_thread_create(coroutine, NULL, 1, 0);
|
||||
EXPECT_TRUE(trd != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd, NULL);
|
||||
}
|
||||
|
||||
VOID TEST(CoroutineTest, StartCoroutineX3)
|
||||
{
|
||||
st_thread_t trd0 = st_thread_create(coroutine, NULL, 1, 0);
|
||||
st_thread_t trd1 = st_thread_create(coroutine, NULL, 1, 0);
|
||||
st_thread_t trd2 = st_thread_create(coroutine, NULL, 1, 0);
|
||||
EXPECT_TRUE(trd0 != NULL && trd1 != NULL && trd2 != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd1, NULL);
|
||||
st_thread_join(trd2, NULL);
|
||||
st_thread_join(trd0, NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// The utest for adding coroutine.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void* coroutine_add(void* arg)
|
||||
{
|
||||
int v = 0;
|
||||
int* pi = (int*)arg;
|
||||
|
||||
// Load the change of arg.
|
||||
while (v != *pi) {
|
||||
v = *pi;
|
||||
st_usleep(0);
|
||||
}
|
||||
|
||||
// Add with const.
|
||||
v += 100;
|
||||
*pi = v;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID TEST(CoroutineTest, StartCoroutineAdd)
|
||||
{
|
||||
int v = 0;
|
||||
st_thread_t trd = st_thread_create(coroutine_add, &v, 1, 0);
|
||||
EXPECT_TRUE(trd != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd, NULL);
|
||||
|
||||
EXPECT_EQ(100, v);
|
||||
}
|
||||
|
||||
VOID TEST(CoroutineTest, StartCoroutineAddX3)
|
||||
{
|
||||
int v = 0;
|
||||
st_thread_t trd0 = st_thread_create(coroutine_add, &v, 1, 0);
|
||||
st_thread_t trd1 = st_thread_create(coroutine_add, &v, 1, 0);
|
||||
st_thread_t trd2 = st_thread_create(coroutine_add, &v, 1, 0);
|
||||
EXPECT_TRUE(trd0 != NULL && trd1 != NULL && trd2 != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd0, NULL);
|
||||
st_thread_join(trd1, NULL);
|
||||
st_thread_join(trd2, NULL);
|
||||
|
||||
EXPECT_EQ(300, v);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// The utest for output params coroutine.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int coroutine_params_x4(int a, int b, int c, int d)
|
||||
{
|
||||
int e = 0;
|
||||
|
||||
st_usleep(0);
|
||||
|
||||
e += a + b + c + d;
|
||||
e += 100;
|
||||
return e;
|
||||
}
|
||||
|
||||
void* coroutine_params(void* arg)
|
||||
{
|
||||
int r0 = coroutine_params_x4(1, 2, 3, 4);
|
||||
*(int*)arg = r0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID TEST(CoroutineTest, StartCoroutineParams)
|
||||
{
|
||||
int r0 = 0;
|
||||
st_thread_t trd = st_thread_create(coroutine_params, &r0, 1, 0);
|
||||
EXPECT_TRUE(trd != NULL);
|
||||
|
||||
// Wait for joinable coroutine to quit.
|
||||
st_thread_join(trd, NULL);
|
||||
|
||||
EXPECT_EQ(110, r0);
|
||||
}
|
||||
|
92
trunk/3rdparty/st-srs/utest/st_utest_tcp.cpp
vendored
Normal file
92
trunk/3rdparty/st-srs/utest/st_utest_tcp.cpp
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/* Copyright (c) 2021 Winlin */
|
||||
|
||||
#include <st_utest.hpp>
|
||||
|
||||
#include <st.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define ST_UTEST_PORT 26878
|
||||
#define ST_UTEST_TIMEOUT (100 * SRS_UTIME_MILLISECONDS)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// The utest for ping-pong TCP server coroutine.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void* tcp_server(void* /*arg*/)
|
||||
{
|
||||
int fd = -1;
|
||||
st_netfd_t stfd = NULL;
|
||||
StFdCleanup(fd, stfd);
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
ST_ASSERT_ERROR(fd == -1, fd, "Create socket");
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(ST_UTEST_PORT);
|
||||
|
||||
int v = 1;
|
||||
int r0 = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int));
|
||||
ST_ASSERT_ERROR(r0, r0, "Set SO_REUSEADDR");
|
||||
|
||||
r0 = ::bind(fd, (const sockaddr*)&addr, sizeof(addr));
|
||||
ST_ASSERT_ERROR(r0, r0, "Bind socket");
|
||||
|
||||
r0 = ::listen(fd, 10);
|
||||
ST_ASSERT_ERROR(r0, r0, "Listen socket");
|
||||
|
||||
stfd = st_netfd_open_socket(fd);
|
||||
ST_ASSERT_ERROR(!stfd, fd, "Open ST socket");
|
||||
|
||||
st_netfd_t client = NULL;
|
||||
StStfdCleanup(client);
|
||||
|
||||
client = st_accept(stfd, NULL, NULL, ST_UTEST_TIMEOUT);
|
||||
ST_ASSERT_ERROR(!client, fd, "Accept client");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* tcp_client(void* /*arg*/)
|
||||
{
|
||||
int fd = -1;
|
||||
st_netfd_t stfd = NULL;
|
||||
StFdCleanup(fd, stfd);
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
ST_ASSERT_ERROR(fd == -1, fd, "Create socket");
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
addr.sin_port = htons(ST_UTEST_PORT);
|
||||
|
||||
stfd = st_netfd_open_socket(fd);
|
||||
ST_ASSERT_ERROR(!stfd, fd, "Open ST socket");
|
||||
|
||||
int r0 = st_connect(stfd, (const sockaddr*)&addr, sizeof(addr), ST_UTEST_TIMEOUT);
|
||||
ST_ASSERT_ERROR(r0, r0, "Connect to server");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID TEST(TcpTest, TcpConnection)
|
||||
{
|
||||
st_thread_t svr = st_thread_create(tcp_server, NULL, 1, 0);
|
||||
EXPECT_TRUE(svr != NULL);
|
||||
|
||||
st_thread_t client = st_thread_create(tcp_client, NULL, 1, 0);
|
||||
EXPECT_TRUE(client != NULL);
|
||||
|
||||
ST_COROUTINE_JOIN(svr, r0);
|
||||
ST_COROUTINE_JOIN(client, r1);
|
||||
|
||||
ST_EXPECT_SUCCESS(r0);
|
||||
ST_EXPECT_SUCCESS(r1);
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ The changelog for SRS.
|
|||
|
||||
## SRS 5.0 Changelog
|
||||
|
||||
* v5.0, 2022-08-06, Support MIPS 64bits for loongson 3A4000/3B3000. v5.0.34
|
||||
* v5.0, 2022-06-29, Support multiple threads by thread pool. v5.0.32
|
||||
* v5.0, 2022-06-28, ST: Support thread-local for multiple threads. v5.0.31
|
||||
* v5.0, 2022-06-17, Merge [#3010](https://github.com/ossrs/srs/pull/3010): SRT: Support Coroutine Native SRT over ST. (#3010). v5.0.30
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 33
|
||||
#define VERSION_REVISION 34
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue