diff --git a/CMakeLists.txt b/CMakeLists.txt index 30076bf26e..0e9b8cbae2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,9 @@ option(BUILD_FUZZ_TESTS "Whether to build fuzz tests" OFF) option(BUILD_BRPC_TOOLS "Whether to build brpc tools" ON) option(DOWNLOAD_GTEST "Download and build a fresh copy of googletest. Requires Internet access." ON) +# see https://github.com/apache/brpc/pull/2727 +add_compile_definitions(NO_PTHREAD_MUTEX_HOOK) + # Enable MACOSX_RPATH. Run "cmake --help-policy CMP0042" for policy details. if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) @@ -113,7 +116,10 @@ configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${PROJECT_SOURCE_DIR}/src/butil list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") find_package(GFLAGS REQUIRED) +find_path(ZLIB_INCLUDE_PATH NAMES zlib.h) +# needed by protobuf +include_directories(${ZLIB_INCLUDE_PATH}) include_directories( ${PROJECT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/bthread/context.cpp b/src/bthread/context.cpp index bafa927d78..d3a25c75e5 100644 --- a/src/bthread/context.cpp +++ b/src/bthread/context.cpp @@ -898,5 +898,129 @@ __asm ( " or $a0, $zero, $zero\n" " bl _exit\n" ); +#endif + +#if defined(BTHREAD_CONTEXT_PLATFORM_linux_mips64) +__asm ( +".text\n" +".globl bthread_jump_fcontext\n" +".align 3\n" +".type bthread_jump_fcontext,@function\n" +".ent bthread_jump_fcontext\n" +"bthread_jump_fcontext:\n" +" # reserve space on stack\n" +" daddiu $sp, $sp, -160\n" +"\n" +" sd $s0, 64($sp) # save S0\n" +" sd $s1, 72($sp) # save S1\n" +" sd $s2, 80($sp) # save S2\n" +" sd $s3, 88($sp) # save S3\n" +" sd $s4, 96($sp) # save S4\n" +" sd $s5, 104($sp) # save S5\n" +" sd $s6, 112($sp) # save S6\n" +" sd $s7, 120($sp) # save S7\n" +" sd $fp, 128($sp) # save FP\n" +" sd $gp, 136($sp) # <<< --- 添加这一行 (SAVE GP)\n" +" sd $ra, 144($sp) # save RA\n" +" sd $ra, 152($sp) # save RA as PC\n" +"\n" +"#if defined(__mips_hard_float)\n" +" s.d $f24, 0($sp) # save F24\n" +" s.d $f25, 8($sp) # save F25\n" +" s.d $f26, 16($sp) # save F26\n" +" s.d $f27, 24($sp) # save F27\n" +" s.d $f28, 32($sp) # save F28\n" +" s.d $f29, 40($sp) # save F29\n" +" s.d $f30, 48($sp) # save F30\n" +" s.d $f31, 56($sp) # save F31\n" +"#endif\n" +"\n" +" # store SP (pointing to old context-data) in v0 as return\n" +" move $v0, $sp\n" +"\n" +" # get SP (pointing to new context-data) from a0 param\n" +" move $sp, $a0\n" +"\n" +"#if defined(__mips_hard_float)\n" +" l.d $f24, 0($sp) # restore F24\n" +" l.d $f25, 8($sp) # restore F25\n" +" l.d $f26, 16($sp) # restore F26\n" +" l.d $f27, 24($sp) # restore F27\n" +" l.d $f28, 32($sp) # restore F28\n" +" l.d $f29, 40($sp) # restore F29\n" +" l.d $f30, 48($sp) # restore F30\n" +" l.d $f31, 56($sp) # restore F31\n" +"#endif\n" +"\n" +" ld $s0, 64($sp) # restore S0\n" +" ld $s1, 72($sp) # restore S1\n" +" ld $s2, 80($sp) # restore S2\n" +" ld $s3, 88($sp) # restore S3\n" +" ld $s4, 96($sp) # restore S4\n" +" ld $s5, 104($sp) # restore S5\n" +" ld $s6, 112($sp) # restore S6\n" +" ld $s7, 120($sp) # restore S7\n" +" ld $fp, 128($sp) # restore FP\n" +" ld $gp, 136($sp) # <<< --- 添加这一行 (RESTORE GP)\n" +" ld $ra, 144($sp) # restore RAa\n" +"\n" +" # load PC\n" +" ld $t9, 152($sp)\n" +"\n" +" # adjust stack\n" +" daddiu $sp, $sp, 160\n" +"\n" +" move $a0, $v0 # move old sp from v0 to a0 as param\n" +" move $v1, $a1 # move *data from a1 to v1 as return\n" +"\n" +" # jump to context\n" +" jr $t9\n" +".end bthread_jump_fcontext\n" +".size bthread_jump_fcontext,.-bthread_jump_fcontext\n" +".section .note.GNU-stack,\"\",%progbits\n" +); +#endif +#if defined(BTHREAD_CONTEXT_PLATFORM_linux_mips64) +__asm ( +".text\n" +".globl bthread_make_fcontext\n" +".align 3\n" +".type bthread_make_fcontext,@function\n" +".ent bthread_make_fcontext\n" +"bthread_make_fcontext:\n" +".set noreorder\n" +".cpload $t9\n" +".set reorder\n" +" # shift address in A0 to lower 16 byte boundary\n" +" li $v1, 0xfffffffffffffff0\n" +" and $v0, $v1, $a0\n" +" # reserve space for context-data on context-stack\n" +" daddiu $v0, $v0, -160\n" +" # third arg of make_fcontext() == address of context-function\n" +" sd $a2, 152($v0)\n" +" # save global pointer in context-data\n" +" sd $gp, 136($v0)\n" +" # pseudo instruction compute abs address of label finish based on GP\n" +" dla $t9, finish\n" +" # save address of finish as return-address for context-function\n" +" # will be entered after context-function returns\n" +" sd $t9, 144($v0)\n" +" jr $ra # return pointer to context-data\n" +"finish:\n" +" # reload our gp register (needed for la)\n" +" daddiu $t0, $sp, -160\n" +" ld $gp, 136($t0)\n" +" # call _exit(0)\n" +" # the previous function should have left the 16 bytes incoming argument\n" +" # area on the stack which we reuse for calling _exit\n" +" dla $t9, _exit\n" +" move $a0, $zero\n" +" jr $t9\n" +".end bthread_make_fcontext\n" +".size bthread_make_fcontext,.-bthread_make_fcontext\n" +".section .note.GNU-stack,\"\",%progbits\n" +); #endif + + diff --git a/src/bthread/context.h b/src/bthread/context.h index 8de85af626..dc6b7af72a 100644 --- a/src/bthread/context.h +++ b/src/bthread/context.h @@ -42,6 +42,9 @@ #elif __loongarch64 #define BTHREAD_CONTEXT_PLATFORM_linux_loongarch64 #define BTHREAD_CONTEXT_CALL_CONVENTION + #elif __mips64 + #define BTHREAD_CONTEXT_PLATFORM_linux_mips64 + #define BTHREAD_CONTEXT_CALL_CONVENTION #endif #elif defined(__MINGW32__) || defined (__MINGW64__) diff --git a/src/bthread/key.cpp b/src/bthread/key.cpp index 1bf5ec899a..b3918e92da 100644 --- a/src/bthread/key.cpp +++ b/src/bthread/key.cpp @@ -34,12 +34,12 @@ namespace bthread { -DEFINE_uint32(key_table_list_size, 4000, +DEFINE_uint64(key_table_list_size, 4000, "The maximum length of the KeyTableList. Once this value is " "exceeded, a portion of the KeyTables will be moved to the " "global free_keytables list."); -DEFINE_uint32(borrow_from_globle_size, 200, +DEFINE_uint64(borrow_from_globle_size, 200, "The maximum number of KeyTables retrieved in a single operation " "from the global free_keytables when no KeyTable exists in the " "current thread's keytable_list."); diff --git a/src/bthread/task_tracer.cpp b/src/bthread/task_tracer.cpp index acdf920891..50a23d88a9 100644 --- a/src/bthread/task_tracer.cpp +++ b/src/bthread/task_tracer.cpp @@ -30,7 +30,7 @@ namespace bthread { DEFINE_bool(enable_fast_unwind, true, "Whether to enable fast unwind"); -DEFINE_uint32(signal_trace_timeout_ms, 50, "Timeout for signal trace in ms"); +DEFINE_uint64(signal_trace_timeout_ms, 50, "Timeout for signal trace in ms"); BUTIL_VALIDATE_GFLAG(signal_trace_timeout_ms, butil::PositiveInteger); extern BAIDU_THREAD_LOCAL TaskMeta* pthread_fake_meta; diff --git a/src/butil/atomicops.h b/src/butil/atomicops.h index cda1529f40..9d7045a98c 100644 --- a/src/butil/atomicops.h +++ b/src/butil/atomicops.h @@ -155,6 +155,8 @@ Atomic64 Release_Load(volatile const Atomic64* ptr); #include "butil/atomicops_internals_x86_gcc.h" #elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY) #include "butil/atomicops_internals_mips_gcc.h" +#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS64_FAMILY) +#include "butil/atomicops_internals_mips64_gcc.h" #elif defined(COMPILER_GCC) && defined(ARCH_CPU_LOONGARCH64_FAMILY) #include "butil/atomicops_internals_loongarch64_gcc.h" #else diff --git a/src/butil/atomicops_internals_mips64_gcc.h b/src/butil/atomicops_internals_mips64_gcc.h new file mode 100644 index 0000000000..4c8a1d221e --- /dev/null +++ b/src/butil/atomicops_internals_mips64_gcc.h @@ -0,0 +1,286 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is an internal atomic implementation, use butil/atomicops.h instead. +// +// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears. + +#ifndef BUTIL_ATOMICOPS_INTERNALS_MIPS64_GCC_H_ +#define BUTIL_ATOMICOPS_INTERNALS_MIPS64_GCC_H_ + +namespace butil { +namespace subtle { + +inline void MemoryBarrier() { + __asm__ __volatile__("sync" : : : "memory"); +} + +// Atomically execute: +// result = *ptr; +// if (*ptr == old_value) +// *ptr = new_value; +// return result; +// +// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". +// Always return the old value of "*ptr" +// +// This routine implies no memory barriers. +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev, tmp; + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "ll %0, %5\n" // prev = *ptr + "bne %0, %3, 2f\n" // if (prev != old_value) goto 2 + "move %2, %4\n" // tmp = new_value + "sc %2, %1\n" // *ptr = tmp (with atomic check) + "beqz %2, 1b\n" // start again on atomic error + "nop\n" // delay slot nop + "2:\n" + ".set pop\n" + : "=&r" (prev), "=m" (*ptr), "=&r" (tmp) + : "Ir" (old_value), "r" (new_value), "m" (*ptr) + : "memory"); + return prev; +} + +// Atomically store new_value into *ptr, returning the previous value held in +// *ptr. This routine implies no memory barriers. +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + Atomic32 temp, old; + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "ll %1, %2\n" // old = *ptr + "move %0, %3\n" // temp = new_value + "sc %0, %2\n" // *ptr = temp (with atomic check) + "beqz %0, 1b\n" // start again on atomic error + "nop\n" // delay slot nop + ".set pop\n" + : "=&r" (temp), "=&r" (old), "=m" (*ptr) + : "r" (new_value), "m" (*ptr) + : "memory"); + + return old; +} + +// Atomically increment *ptr by "increment". Returns the new value of +// *ptr with the increment applied. This routine implies no memory barriers. +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + Atomic32 temp, temp2; + + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "ll %0, %2\n" // temp = *ptr + "addu %1, %0, %3\n" // temp2 = temp + increment + "sc %1, %2\n" // *ptr = temp2 (with atomic check) + "beqz %1, 1b\n" // start again on atomic error + "addu %1, %0, %3\n" // temp2 = temp + increment + ".set pop\n" + : "=&r" (temp), "=&r" (temp2), "=m" (*ptr) + : "Ir" (increment), "m" (*ptr) + : "memory"); + // temp2 now holds the final value. + return temp2; +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + MemoryBarrier(); + Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment); + MemoryBarrier(); + return res; +} + +// "Acquire" operations +// ensure that no later memory access can be reordered ahead of the operation. +// "Release" operations ensure that no previous memory access can be reordered +// after the operation. "Barrier" operations have both "Acquire" and "Release" +// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory +// access. +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + MemoryBarrier(); + return res; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + MemoryBarrier(); + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +// Atomically execute: +// result = *ptr; +// if (*ptr == old_value) +// *ptr = new_value; +// return result; +// +// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". +// Always return the old value of "*ptr" +// +// This routine implies no memory barriers. +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 prev, tmp; + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "lld %0, %5\n" // 64-bit ll + "bne %0, %3, 2f\n" + "move %2, %4\n" // 64-bit move (pseudo-op) + "scd %2, %1\n" // 64-bit sc + "beqz %2, 1b\n" + "nop\n" + "2:\n" + ".set pop\n" + : "=&r" (prev), "=m" (*ptr), "=&r" (tmp) + : "Ir" (old_value), "r" (new_value), "m" (*ptr) + : "memory"); + return prev; +} + +// Atomically store new_value into *ptr, returning the previous value held in +// *ptr. This routine implies no memory barriers. +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + Atomic64 temp, old; + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "lld %1, %2\n" // 64-bit ll + "move %0, %3\n" + "scd %0, %2\n" // 64-bit sc + "beqz %0, 1b\n" + "nop\n" + ".set pop\n" + : "=&r" (temp), "=&r" (old), "=m" (*ptr) + : "r" (new_value), "m" (*ptr) + : "memory"); + + return old; +} + +// Atomically increment *ptr by "increment". Returns the new value of +// *ptr with the increment applied. This routine implies no memory barriers. +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + Atomic64 temp, temp2; + + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "lld %0, %2\n" // 64-bit ll + "daddu %1, %0, %3\n" // 64-bit add + "scd %1, %2\n" // 64-bit sc + "beqz %1, 1b\n" + "daddu %1, %0, %3\n" + ".set pop\n" + : "=&r" (temp), "=&r" (temp2), "=m" (*ptr) + : "Ir" (increment), "m" (*ptr) + : "memory"); + // temp2 now holds the final value. + return temp2; +} + +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + MemoryBarrier(); + Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment); + MemoryBarrier(); + return res; +} + +// "Acquire" operations +// ensure that no later memory access can be reordered ahead of the operation. +// "Release" operations ensure that no previous memory access can be reordered +// after the operation. "Barrier" operations have both "Acquire" and "Release" +// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory +// access. +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + MemoryBarrier(); + return res; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + MemoryBarrier(); + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; +} + +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return *ptr; +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + Atomic64 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { + MemoryBarrier(); + return *ptr; +} + +} // namespace butil::subtle +} // namespace butil + +#endif // BUTIL_ATOMICOPS_INTERNALS_MIPS64_GCC_H_ diff --git a/src/butil/debug/debugger_posix.cc b/src/butil/debug/debugger_posix.cc index 0e4635339f..2c12149683 100644 --- a/src/butil/debug/debugger_posix.cc +++ b/src/butil/debug/debugger_posix.cc @@ -45,10 +45,7 @@ #include "butil/third_party/symbolize/symbolize.h" #endif -#if defined(OS_ANDROID) #include "butil/threading/platform_thread.h" -#endif - namespace butil { namespace debug { diff --git a/src/butil/third_party/valgrind/valgrind.h b/src/butil/third_party/valgrind/valgrind.h index cc2cf3d60a..f7deeadad9 100644 --- a/src/butil/third_party/valgrind/valgrind.h +++ b/src/butil/third_party/valgrind/valgrind.h @@ -692,14 +692,14 @@ typedef _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ - ({ volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + ({ volatile unsigned long long _zzq_args[6]; \ + volatile unsigned long long _zzq_result; \ + _zzq_args[0] = (unsigned long long)(_zzq_request); \ + _zzq_args[1] = (unsigned long long)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long long)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long long)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long long)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long long)(_zzq_arg5); \ __asm__ volatile("move $11, %1\n\t" /*default*/ \ "move $12, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ @@ -872,8 +872,8 @@ typedef #define CALL_FN_W_W(lval, orig, arg1) \ do { \ volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ + volatile unsigned long long _argvec[2]; \ + volatile unsigned long long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ __asm__ volatile( \ @@ -1569,8 +1569,8 @@ typedef arg7) \ do { \ volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ + volatile unsigned long long _argvec[8]; \ + volatile unsigned long long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)(arg1); \ _argvec[2] = (unsigned long)(arg2); \ @@ -2260,8 +2260,8 @@ typedef arg7,arg8,arg9,arg10,arg11,arg12) \ do { \ volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ + volatile unsigned long long _argvec[13]; \ + volatile unsigned long long _res; \ _argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[1] = (unsigned long)arg1; \ _argvec[2] = (unsigned long)arg2; \ diff --git a/src/butil/time.h b/src/butil/time.h index 8b85699840..80b851e072 100644 --- a/src/butil/time.h +++ b/src/butil/time.h @@ -254,6 +254,13 @@ inline uint64_t clock_cycles() { : "=r" (stable_counter), "=r" (counter_id) ); return stable_counter; +#elif defined(__mips64) // 新增对 MIPS64 的支持 + uint64_t count; + __asm__ __volatile__ ( + "dmfc0 %0, $9" + : "=r" (count) + ); + return count; #else #error "unsupported arch" #endif diff --git a/test/bthread_key_unittest.cpp b/test/bthread_key_unittest.cpp index 4319fb4180..3abd3df8dc 100644 --- a/test/bthread_key_unittest.cpp +++ b/test/bthread_key_unittest.cpp @@ -28,8 +28,8 @@ #include "bthread/unstable.h" using namespace bthread; namespace bthread { -DECLARE_uint32(key_table_list_size); -DECLARE_uint32(borrow_from_globle_size); +DECLARE_uint64(key_table_list_size); +DECLARE_uint64(borrow_from_globle_size); class KeyTable; // defined in bthread/key.cpp extern void return_keytable(bthread_keytable_pool_t*, KeyTable*);