diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh index 1998a9374..82d77186d 100755 --- a/trunk/auto/auto_headers.sh +++ b/trunk/auto/auto_headers.sh @@ -171,6 +171,11 @@ if [ $SRS_SANITIZER_LOG == YES ]; then else srs_undefine_macro "SRS_SANITIZER_LOG" $SRS_AUTO_HEADERS_H fi +if [ $SRS_VALGRIND == YES ]; then + srs_define_macro "SRS_VALGRIND" $SRS_AUTO_HEADERS_H +else + srs_undefine_macro "SRS_VALGRIND" $SRS_AUTO_HEADERS_H +fi ##################################################################################### # for embeded. diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 2aedae016..5d6b42374 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 6.0 Changelog +* v6.0, 2024-08-21, Merge [#4150](https://github.com/ossrs/srs/pull/4150): API: Support new HTTP API for VALGRIND. v6.0.149 (#4150) * v6.0, 2024-08-15, Merge [#4144](https://github.com/ossrs/srs/pull/4144): HTTP-FLV: Crash when multiple viewers. v6.0.148 (#4144) * v6.0, 2024-08-15, Merge [#4142](https://github.com/ossrs/srs/pull/4142): Config: Add more utest for env config. v6.0.147 (#4142) * v6.0, 2024-08-14, Merge [#4141](https://github.com/ossrs/srs/pull/4141): Live: Crash for invalid live stream state when unmount HTTP. v6.0.146 (#4141) diff --git a/trunk/src/app/srs_app_gb28181.hpp b/trunk/src/app/srs_app_gb28181.hpp index be6250948..3ac91a3da 100644 --- a/trunk/src/app/srs_app_gb28181.hpp +++ b/trunk/src/app/srs_app_gb28181.hpp @@ -188,7 +188,7 @@ public: void on_media_transport(SrsSharedResource media); // Get the candidate for SDP generation, the public IP address for device to connect to. std::string pip(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); private: @@ -305,7 +305,7 @@ private: public: virtual const SrsContextId& get_id(); virtual std::string desc(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); private: @@ -333,7 +333,7 @@ public: // Interface ISrsStartable public: virtual srs_error_t start(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); private: @@ -362,7 +362,7 @@ public: // Interface ISrsStartable public: virtual srs_error_t start(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); private: @@ -422,7 +422,7 @@ public: public: virtual const SrsContextId& get_id(); virtual std::string desc(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); private: diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index c8bc71010..b1bd339a4 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -31,6 +31,11 @@ using namespace std; #include #include +#ifdef SRS_VALGRIND +#include +#include +#endif + #if defined(__linux__) || defined(SRS_OSX) #include #endif @@ -267,6 +272,7 @@ srs_error_t SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r urls->set("clusters", SrsJsonAny::str("origin cluster server API")); urls->set("perf", SrsJsonAny::str("System performance stat")); urls->set("tcmalloc", SrsJsonAny::str("tcmalloc api with params ?page=summary|api")); + urls->set("valgrind", SrsJsonAny::str("valgrind api with params ?check=full|added|changed|new|quick")); SrsJsonObject* tests = SrsJsonAny::object(); obj->set("tests", tests); @@ -1090,6 +1096,100 @@ srs_error_t SrsGoApiTcmalloc::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess } #endif +#ifdef SRS_VALGRIND + +SrsGoApiValgrind::SrsGoApiValgrind() +{ + trd_ = NULL; +} + +SrsGoApiValgrind::~SrsGoApiValgrind() +{ + srs_freep(trd_); +} + +srs_error_t SrsGoApiValgrind::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) +{ + srs_error_t err = srs_success; + + if (!trd_) { + trd_ = new SrsSTCoroutine("valgrind", this, _srs_context->get_id()); + if ((err = trd_->start()) != srs_success) { + return srs_error_wrap(err, "start"); + } + } + + string check = r->query_get("check"); + srs_trace("query check=%s", check.c_str()); + + // Must be full|added|changed|new|quick, set to full for other values. + if (check != "full" && check != "added" && check != "changed" && check != "new" && check != "quick") { + srs_warn("force set check=%s to full", check.c_str()); + check = "full"; + } + + // By default, response the json style response. + SrsUniquePtr obj(SrsJsonAny::object()); + + obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); + + SrsJsonObject* res = SrsJsonAny::object(); + res->set("check", SrsJsonAny::str(check.c_str())); + res->set("help", SrsJsonAny::str("?check=full|added|changed|new|quick")); + res->set("see", SrsJsonAny::str("https://valgrind.org/docs/manual/mc-manual.html")); + obj->set("data", res); + + // Does a memory check later. + if (check == "full") { + res->set("call", SrsJsonAny::str("VALGRIND_DO_LEAK_CHECK")); + } else if (check == "quick") { + res->set("call", SrsJsonAny::str("VALGRIND_DO_QUICK_LEAK_CHECK")); + } else if (check == "added") { + res->set("call", SrsJsonAny::str("VALGRIND_DO_ADDED_LEAK_CHECK")); + } else if (check == "changed") { + res->set("call", SrsJsonAny::str("VALGRIND_DO_CHANGED_LEAK_CHECK")); + } else if (check == "new") { + res->set("call", SrsJsonAny::str("VALGRIND_DO_NEW_LEAK_CHECK")); + } + task_ = check; + + return srs_api_response(w, r, obj->dumps()); +} + +srs_error_t SrsGoApiValgrind::cycle() +{ + srs_error_t err = srs_success; + + while (true) { + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "pull"); + } + + std::string check = task_; + task_ = ""; + + if (!check.empty()) { + srs_trace("do memory check=%s", check.c_str()); + } + + if (check == "full") { + VALGRIND_DO_LEAK_CHECK; + } else if (check == "quick") { + VALGRIND_DO_QUICK_LEAK_CHECK; + } else if (check == "added") { + VALGRIND_DO_ADDED_LEAK_CHECK; + } else if (check == "changed") { + VALGRIND_DO_CHANGED_LEAK_CHECK; + } else if (check == "new") { + VALGRIND_DO_NEW_LEAK_CHECK; + } + + srs_usleep(3 * SRS_UTIME_SECONDS); + } + + return err; +} +#endif SrsGoApiMetrics::SrsGoApiMetrics() { diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 8bcb30e50..8789d42e9 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -216,6 +216,23 @@ public: }; #endif +#ifdef SRS_VALGRIND +class SrsGoApiValgrind : public ISrsHttpHandler, public ISrsCoroutineHandler +{ +private: + SrsCoroutine* trd_; + std::string task_; +public: + SrsGoApiValgrind(); + virtual ~SrsGoApiValgrind(); +public: + virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); +// Interface ISrsCoroutineHandler +public: + virtual srs_error_t cycle(); +}; +#endif + class SrsGoApiMetrics : public ISrsHttpHandler { private: diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 57f984a49..9d1cc1055 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -94,7 +94,7 @@ public: // Interface ISrsStartable public: virtual srs_error_t start(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); private: diff --git a/trunk/src/app/srs_app_recv_thread.hpp b/trunk/src/app/srs_app_recv_thread.hpp index 5fa011db5..7d29a4b39 100644 --- a/trunk/src/app/srs_app_recv_thread.hpp +++ b/trunk/src/app/srs_app_recv_thread.hpp @@ -204,7 +204,7 @@ public: virtual srs_error_t start(); public: virtual srs_error_t pull(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); }; diff --git a/trunk/src/app/srs_app_rtmp_conn.hpp b/trunk/src/app/srs_app_rtmp_conn.hpp index 8c86627fe..9a772ffb7 100644 --- a/trunk/src/app/srs_app_rtmp_conn.hpp +++ b/trunk/src/app/srs_app_rtmp_conn.hpp @@ -181,7 +181,7 @@ public: // when client cycle thread stop, invoke the on_thread_stop(), which will use server // To remove the client by server->remove(this). virtual srs_error_t start(); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: // The thread cycle function, // when serve connection completed, terminate the loop which will terminate the thread, diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index aff62f02e..16bc99e8c 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -773,9 +773,17 @@ srs_error_t SrsServer::http_handle() // The test api for get tcmalloc stats. // @see Memory Introspection in https://gperftools.github.io/gperftools/tcmalloc.html if ((err = http_api_mux->handle("/api/v1/tcmalloc", new SrsGoApiTcmalloc())) != srs_success) { - return srs_error_wrap(err, "handle tests errors"); + return srs_error_wrap(err, "handle tcmalloc errors"); } #endif + +#ifdef SRS_VALGRIND + // The test api for valgrind. See VALGRIND_DO_LEAK_CHECK in https://valgrind.org/docs/manual/mc-manual.html + if ((err = http_api_mux->handle("/api/v1/valgrind", new SrsGoApiValgrind())) != srs_success) { + return srs_error_wrap(err, "handle valgrind errors"); + } +#endif + // metrics by prometheus if ((err = http_api_mux->handle("/metrics", new SrsGoApiMetrics())) != srs_success) { return srs_error_wrap(err, "handle tests errors"); diff --git a/trunk/src/app/srs_app_st.hpp b/trunk/src/app/srs_app_st.hpp index d7315b20c..11f2c2195 100644 --- a/trunk/src/app/srs_app_st.hpp +++ b/trunk/src/app/srs_app_st.hpp @@ -291,7 +291,7 @@ public: public: virtual const SrsContextId& cid(); virtual void set_cid(const SrsContextId& cid); -// Interface ISrsOneCycleThreadHandler +// Interface ISrsCoroutineHandler public: virtual srs_error_t cycle(); // Interface ISrsResource diff --git a/trunk/src/core/srs_core_version6.hpp b/trunk/src/core/srs_core_version6.hpp index 33a00d8c9..9e3f4b4a1 100644 --- a/trunk/src/core/srs_core_version6.hpp +++ b/trunk/src/core/srs_core_version6.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 6 #define VERSION_MINOR 0 -#define VERSION_REVISION 148 +#define VERSION_REVISION 149 #endif