mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 19:31:53 +00:00
merge from srs2
This commit is contained in:
commit
9dce971d57
18 changed files with 398 additions and 39 deletions
|
@ -250,7 +250,7 @@ Compare SRS with other media server.
|
|||
| RTMP Edge | Stable | X | X | Stable | X |
|
||||
| RTMP Backup | Stable | X | X | X | X |
|
||||
| VHOST | Stable | X | X | Stable | Stable |
|
||||
| Reload | Stable | Stable | X | X | X |
|
||||
| Reload | Stable | X | X | X | X |
|
||||
| Forward | Stable | X | X | X | X |
|
||||
| ATC | Stable | X | X | X | X |
|
||||
|
||||
|
@ -312,6 +312,7 @@ Remark:
|
|||
1. HLS aonly: The HLS audio only streaming delivery.
|
||||
1. BW check: The bandwidth check.
|
||||
1. Security: To allow or deny stream publish or play.
|
||||
1. Reload: Nginx supports reload, but not nginx-rtmp.
|
||||
|
||||
## Releases
|
||||
|
||||
|
@ -346,6 +347,8 @@ Remark:
|
|||
* v3.0, 2015-03-15, fork srs2 and start srs3. 3.0.0
|
||||
|
||||
### SRS 2.0 history
|
||||
|
||||
* v2.0, 2015-05-30, fix [#209](https://github.com/simple-rtmp-server/srs/issues/209) cleanup hls when stop and timeout. 2.0.173.
|
||||
* v2.0, 2015-05-29, fix [#409](https://github.com/simple-rtmp-server/srs/issues/409) support pure video hls. 2.0.172.
|
||||
* v2.0, 2015-05-28, support [srs-dolphin][srs-dolphin], the multiple-process SRS.
|
||||
* v2.0, 2015-05-24, fix [#404](https://github.com/simple-rtmp-server/srs/issues/404) register handler then start http thread. 2.0.167.
|
||||
|
|
|
@ -618,9 +618,14 @@ vhost with-hls.srs.com {
|
|||
# h264, vn
|
||||
# default: h264
|
||||
hls_vcodec h264;
|
||||
# whether cleanup the old ts files.
|
||||
# whether cleanup the old expired ts files.
|
||||
# default: on
|
||||
hls_cleanup on;
|
||||
# the timeout in seconds to dispose the hls,
|
||||
# dispose is to remove all hls files, m3u8 and ts files.
|
||||
# when timeout or server terminate, dispose hls.
|
||||
# default: 300
|
||||
hls_dispose 300;
|
||||
# the max size to notify hls,
|
||||
# to read max bytes from ts of specified cdn network,
|
||||
# @remark only used when on_hls_notify is config.
|
||||
|
|
|
@ -109,12 +109,12 @@ stop() {
|
|||
ok_msg "Stopping SRS(pid ${srs_pid})..."
|
||||
|
||||
# process exists, try to kill to stop normally
|
||||
for((i=0;i<30;i++)); do
|
||||
for((i=0;i<100;i++)); do
|
||||
load_process_info
|
||||
if [[ 0 -eq $? ]]; then
|
||||
kill -s SIGTERM ${srs_pid} 2>/dev/null
|
||||
ret=$?; if [[ 0 -ne $ret ]]; then failed_msg "send signal SIGTERM failed ret=$ret"; return $ret; fi
|
||||
sleep 0.1
|
||||
sleep 0.3
|
||||
else
|
||||
ok_msg "SRS stopped by SIGTERM"
|
||||
# delete the pid file when stop success.
|
||||
|
|
|
@ -1564,7 +1564,8 @@ int SrsConfig::check_config()
|
|||
string m = conf->at(j)->name.c_str();
|
||||
if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
|
||||
&& m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
|
||||
&& m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" && m != "hls_wait_keyframe"
|
||||
&& m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify"
|
||||
&& m != "hls_wait_keyframe" && m != "hls_dispose"
|
||||
) {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3561,6 +3562,24 @@ bool SrsConfig::get_hls_cleanup(string vhost)
|
|||
return SRS_CONF_PERFER_TRUE(conf->arg0());
|
||||
}
|
||||
|
||||
int SrsConfig::get_hls_dispose(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_hls(vhost);
|
||||
|
||||
int DEFAULT = 300;
|
||||
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("hls_dispose");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
|
||||
bool SrsConfig::get_hls_wait_keyframe(string vhost)
|
||||
{
|
||||
SrsConfDirective* hls = get_hls(vhost);
|
||||
|
|
|
@ -984,6 +984,10 @@ public:
|
|||
* whether cleanup the old ts files.
|
||||
*/
|
||||
virtual bool get_hls_cleanup(std::string vhost);
|
||||
/**
|
||||
* the timeout to dispose the hls.
|
||||
*/
|
||||
virtual int get_hls_dispose(std::string vhost);
|
||||
/**
|
||||
* whether reap the ts when got keyframe.
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,7 @@ using namespace std;
|
|||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_app_config.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_FFMPEG_STUB
|
||||
|
||||
|
@ -51,6 +52,7 @@ using namespace std;
|
|||
SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
|
||||
{
|
||||
started = false;
|
||||
fast_stopped = false;
|
||||
pid = -1;
|
||||
ffmpeg = ffmpeg_bin;
|
||||
|
||||
|
@ -402,6 +404,10 @@ int SrsFFMPEG::start()
|
|||
|
||||
// child process: ffmpeg encoder engine.
|
||||
if (pid == 0) {
|
||||
// ignore the SIGINT and SIGTERM
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
||||
// redirect logs to file.
|
||||
int log_fd = -1;
|
||||
int flags = O_CREAT|O_WRONLY|O_APPEND;
|
||||
|
@ -479,6 +485,11 @@ int SrsFFMPEG::cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
// ffmpeg is prepare to stop, donot cycle.
|
||||
if (fast_stopped) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
pid_t p = waitpid(pid, &status, WNOHANG);
|
||||
|
||||
|
@ -509,24 +520,35 @@ void SrsFFMPEG::stop()
|
|||
// when rewind, upstream will stop publish(unpublish),
|
||||
// unpublish event will stop all ffmpeg encoders,
|
||||
// then publish will start all ffmpeg encoders.
|
||||
if (pid > 0) {
|
||||
if (kill(pid, SIGKILL) < 0) {
|
||||
srs_warn("kill the encoder failed, ignored. pid=%d", pid);
|
||||
}
|
||||
|
||||
// wait for the ffmpeg to quit.
|
||||
// ffmpeg will gracefully quit if signal is:
|
||||
// 1) SIGHUP 2) SIGINT 3) SIGQUIT
|
||||
// other signals, directly exit(123), for example:
|
||||
// 9) SIGKILL 15) SIGTERM
|
||||
int status = 0;
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
srs_warn("wait the encoder quit failed, ignored. pid=%d", pid);
|
||||
}
|
||||
|
||||
srs_trace("stop the encoder success. pid=%d", pid);
|
||||
pid = -1;
|
||||
int ret = srs_kill_forced(pid);
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
srs_warn("ignore kill the encoder failed, pid=%d. ret=%d", pid, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// terminated, set started to false to stop the cycle.
|
||||
started = false;
|
||||
}
|
||||
|
||||
void SrsFFMPEG::fast_stop()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!started) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kill(pid, SIGTERM) < 0) {
|
||||
ret = ERROR_SYSTEM_KILL;
|
||||
srs_warn("ignore fast stop ffmpeg failed, pid=%d. ret=%d", pid, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,6 +45,8 @@ class SrsFFMPEG
|
|||
{
|
||||
private:
|
||||
bool started;
|
||||
// whether SIGINT send but need to wait or SIGKILL.
|
||||
bool fast_stopped;
|
||||
pid_t pid;
|
||||
private:
|
||||
std::string log_file;
|
||||
|
@ -83,7 +85,25 @@ public:
|
|||
virtual int initialize_copy();
|
||||
virtual int start();
|
||||
virtual int cycle();
|
||||
/**
|
||||
* send SIGTERM then SIGKILL to ensure the process stopped.
|
||||
* the stop will wait [0, SRS_PROCESS_QUIT_TIMEOUT_MS] depends on the
|
||||
* process quit timeout.
|
||||
* @remark use fast_stop before stop one by one, when got lots of process to quit.
|
||||
*/
|
||||
virtual void stop();
|
||||
public:
|
||||
/**
|
||||
* the fast stop is to send a SIGTERM.
|
||||
* for example, the ingesters owner lots of FFMPEG, it will take a long time
|
||||
* to stop one by one, instead the ingesters can fast_stop all FFMPEG, then
|
||||
* wait one by one to stop, it's more faster.
|
||||
* @remark user must use stop() to ensure the ffmpeg to stopped.
|
||||
* @remark we got N processes to stop, compare the time we spend,
|
||||
* when use stop without fast_stop, we spend maybe [0, SRS_PROCESS_QUIT_TIMEOUT_MS * N]
|
||||
* but use fast_stop then stop, the time is almost [0, SRS_PROCESS_QUIT_TIMEOUT_MS].
|
||||
*/
|
||||
virtual void fast_stop();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -305,6 +305,37 @@ SrsHlsMuxer::~SrsHlsMuxer()
|
|||
srs_freep(context);
|
||||
}
|
||||
|
||||
void SrsHlsMuxer::dispose()
|
||||
{
|
||||
if (should_write_file) {
|
||||
std::vector<SrsHlsSegment*>::iterator it;
|
||||
for (it = segments.begin(); it != segments.end(); ++it) {
|
||||
SrsHlsSegment* segment = *it;
|
||||
if (unlink(segment->full_path.c_str()) < 0) {
|
||||
srs_warn("dispose unlink path failed, file=%s.", segment->full_path.c_str());
|
||||
}
|
||||
srs_freep(segment);
|
||||
}
|
||||
segments.clear();
|
||||
|
||||
if (current) {
|
||||
std::string path = current->full_path + ".tmp";
|
||||
if (unlink(path.c_str()) < 0) {
|
||||
srs_warn("dispose unlink path failed, file=%s", path.c_str());
|
||||
}
|
||||
srs_freep(current);
|
||||
}
|
||||
|
||||
if (unlink(m3u8.c_str()) < 0) {
|
||||
srs_warn("dispose unlink path failed. file=%s", m3u8.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: FIXME: support hls dispose in HTTP cache.
|
||||
|
||||
srs_trace("gracefully dispose hls %s", req? req->get_stream_url().c_str() : "");
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::sequence_no()
|
||||
{
|
||||
return _sequence_no;
|
||||
|
@ -720,6 +751,9 @@ int SrsHlsMuxer::segment_close(string log_desc)
|
|||
std::string tmp_file = current->full_path + ".tmp";
|
||||
if (should_write_file) {
|
||||
unlink(tmp_file.c_str());
|
||||
if (unlink(tmp_file.c_str()) < 0) {
|
||||
srs_warn("drop unlink path failed, file=%s.", tmp_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
srs_freep(current);
|
||||
|
@ -754,7 +788,9 @@ int SrsHlsMuxer::segment_close(string log_desc)
|
|||
SrsHlsSegment* segment = segment_to_remove[i];
|
||||
|
||||
if (hls_cleanup) {
|
||||
unlink(segment->full_path.c_str());
|
||||
if (unlink(segment->full_path.c_str()) < 0) {
|
||||
srs_warn("cleanup unlink path failed, file=%s.", segment->full_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
srs_freep(segment);
|
||||
|
@ -1085,6 +1121,8 @@ SrsHls::SrsHls()
|
|||
handler = NULL;
|
||||
|
||||
hls_enabled = false;
|
||||
hls_can_dispose = false;
|
||||
last_update_time = 0;
|
||||
|
||||
codec = new SrsAvcAacCodec();
|
||||
sample = new SrsCodecSample();
|
||||
|
@ -1109,6 +1147,46 @@ SrsHls::~SrsHls()
|
|||
srs_freep(pprint);
|
||||
}
|
||||
|
||||
void SrsHls::dispose()
|
||||
{
|
||||
if (hls_enabled) {
|
||||
on_unpublish();
|
||||
}
|
||||
|
||||
muxer->dispose();
|
||||
}
|
||||
|
||||
int SrsHls::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_info("hls cycle for source %d", source->source_id());
|
||||
|
||||
if (last_update_time <= 0) {
|
||||
last_update_time = srs_get_system_time_ms();
|
||||
}
|
||||
|
||||
if (!_req) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hls_dispose = _srs_config->get_hls_dispose(_req->vhost) * 1000;
|
||||
if (srs_get_system_time_ms() - last_update_time <= hls_dispose) {
|
||||
return ret;
|
||||
}
|
||||
last_update_time = srs_get_system_time_ms();
|
||||
|
||||
if (!hls_can_dispose) {
|
||||
return ret;
|
||||
}
|
||||
hls_can_dispose = false;
|
||||
|
||||
srs_trace("hls cycle to dispose hls %s, timeout=%dms", _req->get_stream_url().c_str(), hls_dispose);
|
||||
dispose();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHls::initialize(SrsSource* s, ISrsHlsHandler* h)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -1127,6 +1205,11 @@ int SrsHls::on_publish(SrsRequest* req)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
_req = req;
|
||||
|
||||
// update the hls time, for hls_dispose.
|
||||
last_update_time = srs_get_system_time_ms();
|
||||
|
||||
// support multiple publish.
|
||||
if (hls_enabled) {
|
||||
return ret;
|
||||
|
@ -1144,6 +1227,9 @@ int SrsHls::on_publish(SrsRequest* req)
|
|||
// if enabled, open the muxer.
|
||||
hls_enabled = true;
|
||||
|
||||
// ok, the hls can be dispose, or need to be dispose.
|
||||
hls_can_dispose = true;
|
||||
|
||||
// notice the source to get the cached sequence header.
|
||||
// when reload to start hls, hls will never get the sequence header in stream,
|
||||
// use the SrsSource.on_hls_start to push the sequence header to HLS.
|
||||
|
@ -1195,6 +1281,9 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio)
|
|||
if (!hls_enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update the hls time, for hls_dispose.
|
||||
last_update_time = srs_get_system_time_ms();
|
||||
|
||||
SrsSharedPtrMessage* audio = shared_audio->copy();
|
||||
SrsAutoFree(SrsSharedPtrMessage, audio);
|
||||
|
@ -1256,6 +1345,9 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video)
|
|||
if (!hls_enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update the hls time, for hls_dispose.
|
||||
last_update_time = srs_get_system_time_ms();
|
||||
|
||||
SrsSharedPtrMessage* video = shared_video->copy();
|
||||
SrsAutoFree(SrsSharedPtrMessage, video);
|
||||
|
|
|
@ -259,6 +259,8 @@ private:
|
|||
public:
|
||||
SrsHlsMuxer();
|
||||
virtual ~SrsHlsMuxer();
|
||||
public:
|
||||
virtual void dispose();
|
||||
public:
|
||||
virtual int sequence_no();
|
||||
virtual std::string ts_url();
|
||||
|
@ -379,7 +381,11 @@ private:
|
|||
SrsHlsCache* hls_cache;
|
||||
ISrsHlsHandler* handler;
|
||||
private:
|
||||
SrsRequest* _req;
|
||||
bool hls_enabled;
|
||||
bool hls_can_dispose;
|
||||
int64_t last_update_time;
|
||||
private:
|
||||
SrsSource* source;
|
||||
SrsAvcAacCodec* codec;
|
||||
SrsCodecSample* sample;
|
||||
|
@ -402,6 +408,9 @@ private:
|
|||
public:
|
||||
SrsHls();
|
||||
virtual ~SrsHls();
|
||||
public:
|
||||
virtual void dispose();
|
||||
virtual int cycle();
|
||||
public:
|
||||
/**
|
||||
* initialize the hls by handler and source.
|
||||
|
|
|
@ -51,6 +51,11 @@ SrsIngesterFFMPEG::~SrsIngesterFFMPEG()
|
|||
srs_freep(ffmpeg);
|
||||
}
|
||||
|
||||
void SrsIngesterFFMPEG::fast_stop()
|
||||
{
|
||||
ffmpeg->fast_stop();
|
||||
}
|
||||
|
||||
SrsIngester::SrsIngester()
|
||||
{
|
||||
_srs_config->subscribe(this);
|
||||
|
@ -159,6 +164,23 @@ int SrsIngester::parse_engines(SrsConfDirective* vhost, SrsConfDirective* ingest
|
|||
return ret;
|
||||
}
|
||||
|
||||
void SrsIngester::dispose()
|
||||
{
|
||||
// first, use fast stop to notice all FFMPEG to quit gracefully.
|
||||
std::vector<SrsIngesterFFMPEG*>::iterator it;
|
||||
for (it = ingesters.begin(); it != ingesters.end(); ++it) {
|
||||
SrsIngesterFFMPEG* ingester = *it;
|
||||
ingester->fast_stop();
|
||||
}
|
||||
|
||||
if (!ingesters.empty()) {
|
||||
srs_trace("fast stop all ingesters ok.");
|
||||
}
|
||||
|
||||
// then, use stop to wait FFMPEG quit one by one and send SIGKILL if needed.
|
||||
stop();
|
||||
}
|
||||
|
||||
void SrsIngester::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
|
|
|
@ -52,6 +52,9 @@ public:
|
|||
|
||||
SrsIngesterFFMPEG(SrsFFMPEG* _ffmpeg, std::string _vhost, std::string _id);
|
||||
virtual ~SrsIngesterFFMPEG();
|
||||
|
||||
// @see SrsFFMPEG.fast_stop().
|
||||
virtual void fast_stop();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -69,6 +72,8 @@ private:
|
|||
public:
|
||||
SrsIngester();
|
||||
virtual ~SrsIngester();
|
||||
public:
|
||||
virtual void dispose();
|
||||
public:
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
|
|
|
@ -480,6 +480,7 @@ SrsServer::SrsServer()
|
|||
{
|
||||
signal_reload = false;
|
||||
signal_gmc_stop = false;
|
||||
signal_gracefully_quit = false;
|
||||
pid_fd = -1;
|
||||
|
||||
signal_manager = NULL;
|
||||
|
@ -519,7 +520,7 @@ void SrsServer::destroy()
|
|||
close_listeners(SrsListenerHttpStream);
|
||||
|
||||
#ifdef SRS_AUTO_INGEST
|
||||
ingester->stop();
|
||||
ingester->dispose();
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_API
|
||||
|
@ -555,6 +556,21 @@ void SrsServer::destroy()
|
|||
// and segment fault.
|
||||
}
|
||||
|
||||
void SrsServer::dispose()
|
||||
{
|
||||
_srs_config->unsubscribe(this);
|
||||
|
||||
#ifdef SRS_AUTO_INGEST
|
||||
ingester->dispose();
|
||||
srs_trace("gracefully dispose ingesters");
|
||||
#endif
|
||||
|
||||
SrsSource::dispose_all();
|
||||
srs_trace("gracefully dispose sources");
|
||||
|
||||
srs_trace("terminate server");
|
||||
}
|
||||
|
||||
int SrsServer::initialize(ISrsServerCycle* cycle_handler)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -831,6 +847,7 @@ int SrsServer::cycle()
|
|||
srs_warn("system quit");
|
||||
#else
|
||||
srs_warn("main cycle terminated, system quit normally.");
|
||||
dispose();
|
||||
exit(0);
|
||||
#endif
|
||||
|
||||
|
@ -877,9 +894,9 @@ void SrsServer::on_signal(int signo)
|
|||
return;
|
||||
}
|
||||
|
||||
if (signo == SIGTERM) {
|
||||
srs_trace("user terminate program");
|
||||
exit(0);
|
||||
if (signo == SIGTERM && !signal_gracefully_quit) {
|
||||
srs_trace("user terminate program, gracefully quit.");
|
||||
signal_gracefully_quit = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -903,7 +920,7 @@ int SrsServer::do_cycle()
|
|||
|
||||
// the deamon thread, update the time cache
|
||||
while (true) {
|
||||
if(handler && (ret = handler->on_cycle(conns.size())) != ERROR_SUCCESS){
|
||||
if(handler && (ret = handler->on_cycle((int)conns.size())) != ERROR_SUCCESS){
|
||||
srs_error("cycle handle failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -917,12 +934,18 @@ int SrsServer::do_cycle()
|
|||
|
||||
for (int i = 0; i < temp_max; i++) {
|
||||
st_usleep(SRS_SYS_CYCLE_INTERVAL * 1000);
|
||||
|
||||
// gracefully quit for SIGINT or SIGTERM.
|
||||
if (signal_gracefully_quit) {
|
||||
srs_trace("cleanup for gracefully terminate.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// for gperf heap checker,
|
||||
// @see: research/gperftools/heap-checker/heap_checker.cc
|
||||
// if user interrupt the program, exit to check mem leak.
|
||||
// but, if gperf, use reload to ensure main return normally,
|
||||
// because directly exit will cause core-dump.
|
||||
// for gperf heap checker,
|
||||
// @see: research/gperftools/heap-checker/heap_checker.cc
|
||||
// if user interrupt the program, exit to check mem leak.
|
||||
// but, if gperf, use reload to ensure main return normally,
|
||||
// because directly exit will cause core-dump.
|
||||
#ifdef SRS_AUTO_GPERF_MC
|
||||
if (signal_gmc_stop) {
|
||||
srs_warn("gmc got singal to stop server.");
|
||||
|
@ -930,6 +953,7 @@ int SrsServer::do_cycle()
|
|||
}
|
||||
#endif
|
||||
|
||||
// do reload the config.
|
||||
if (signal_reload) {
|
||||
signal_reload = false;
|
||||
srs_info("get signal reload, to reload the config.");
|
||||
|
@ -941,6 +965,11 @@ int SrsServer::do_cycle()
|
|||
srs_trace("reload config success.");
|
||||
}
|
||||
|
||||
// notice the stream sources to cycle.
|
||||
if ((ret = SrsSource::cycle_all()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update the cache time
|
||||
if ((i % SRS_SYS_TIME_RESOLUTION_MS_TIMES) == 0) {
|
||||
srs_info("update current time cache.");
|
||||
|
|
|
@ -275,16 +275,22 @@ private:
|
|||
*/
|
||||
bool signal_reload;
|
||||
bool signal_gmc_stop;
|
||||
bool signal_gracefully_quit;
|
||||
public:
|
||||
SrsServer();
|
||||
virtual ~SrsServer();
|
||||
public:
|
||||
private:
|
||||
/**
|
||||
* the destroy is for gmc to analysis the memory leak,
|
||||
* if not destroy global/static data, the gmc will warning memory leak.
|
||||
* in service, server never destroy, directly exit when restart.
|
||||
*/
|
||||
virtual void destroy();
|
||||
/**
|
||||
* when SIGTERM, SRS should do cleanup, for example,
|
||||
* to stop all ingesters, cleanup HLS and dvr.
|
||||
*/
|
||||
virtual void dispose();
|
||||
// server startup workflow, @see run_master()
|
||||
public:
|
||||
virtual int initialize(ISrsServerCycle* cycle_handler);
|
||||
|
|
|
@ -771,6 +771,32 @@ SrsSource* SrsSource::fetch(std::string vhost, std::string app, std::string stre
|
|||
return source;
|
||||
}
|
||||
|
||||
void SrsSource::dispose_all()
|
||||
{
|
||||
std::map<std::string, SrsSource*>::iterator it;
|
||||
for (it = pool.begin(); it != pool.end(); ++it) {
|
||||
SrsSource* source = it->second;
|
||||
source->dispose();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int SrsSource::cycle_all()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// TODO: FIXME: support remove dead source for a long time.
|
||||
std::map<std::string, SrsSource*>::iterator it;
|
||||
for (it = pool.begin(); it != pool.end(); ++it) {
|
||||
SrsSource* source = it->second;
|
||||
if ((ret = source->cycle()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsSource::destroy()
|
||||
{
|
||||
std::map<std::string, SrsSource*>::iterator it;
|
||||
|
@ -909,6 +935,26 @@ SrsSource::~SrsSource()
|
|||
srs_freep(_req);
|
||||
}
|
||||
|
||||
void SrsSource::dispose()
|
||||
{
|
||||
#ifdef SRS_AUTO_HLS
|
||||
hls->dispose();
|
||||
#endif
|
||||
}
|
||||
|
||||
int SrsSource::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
#ifdef SRS_AUTO_HLS
|
||||
if ((ret = hls->cycle()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h, ISrsHlsHandler* hh)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
|
|
@ -410,6 +410,11 @@ public:
|
|||
* get the exists source by stream info(vhost, app, stream), NULL when not exists.
|
||||
*/
|
||||
static SrsSource* fetch(std::string vhost, std::string app, std::string stream);
|
||||
/**
|
||||
* dispose and cycle all sources.
|
||||
*/
|
||||
static void dispose_all();
|
||||
static int cycle_all();
|
||||
/**
|
||||
* when system exit, destroy the sources,
|
||||
* for gmc to analysis mem leaks.
|
||||
|
@ -486,6 +491,9 @@ private:
|
|||
public:
|
||||
SrsSource();
|
||||
virtual ~SrsSource();
|
||||
public:
|
||||
virtual void dispose();
|
||||
virtual int cycle();
|
||||
// initialize, get and setter.
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <unistd.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef SRS_OSX
|
||||
#include <sys/sysctl.h>
|
||||
|
@ -43,6 +44,9 @@ using namespace std;
|
|||
#include <srs_app_json.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
|
||||
// the longest time to wait for a process to quit.
|
||||
#define SRS_PROCESS_QUIT_TIMEOUT_MS 1000
|
||||
|
||||
int srs_socket_connect(string server, int port, int64_t timeout, st_netfd_t* pstfd)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -222,6 +226,62 @@ void srs_parse_endpoint(string ip_port, string& ip, int& port)
|
|||
port = ::atoi(the_port.c_str());
|
||||
}
|
||||
|
||||
int srs_kill_forced(int& pid)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (pid <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// first, try kill by SIGTERM.
|
||||
if (kill(pid, SIGTERM) < 0) {
|
||||
return ERROR_SYSTEM_KILL;
|
||||
}
|
||||
|
||||
// wait to quit.
|
||||
srs_trace("send SIGTERM to pid=%d", pid);
|
||||
for (int i = 0; i < SRS_PROCESS_QUIT_TIMEOUT_MS / 10; i++) {
|
||||
int status = 0;
|
||||
pid_t qpid = -1;
|
||||
if ((qpid = waitpid(pid, &status, WNOHANG)) < 0) {
|
||||
return ERROR_SYSTEM_KILL;
|
||||
}
|
||||
|
||||
// 0 is not quit yet.
|
||||
if (qpid == 0) {
|
||||
st_usleep(10 * 1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
// killed, set pid to -1.
|
||||
srs_trace("SIGTERM stop process pid=%d ok.", pid);
|
||||
pid = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// then, try kill by SIGKILL.
|
||||
if (kill(pid, SIGKILL) < 0) {
|
||||
return ERROR_SYSTEM_KILL;
|
||||
}
|
||||
|
||||
// wait for the process to quit.
|
||||
// for example, ffmpeg will gracefully quit if signal is:
|
||||
// 1) SIGHUP 2) SIGINT 3) SIGQUIT
|
||||
// other signals, directly exit(123), for example:
|
||||
// 9) SIGKILL 15) SIGTERM
|
||||
int status = 0;
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
return ERROR_SYSTEM_KILL;
|
||||
}
|
||||
|
||||
srs_trace("SIGKILL stop process pid=%d ok.", pid);
|
||||
pid = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SrsRusage _srs_system_rusage;
|
||||
|
||||
SrsRusage::SrsRusage()
|
||||
|
@ -422,7 +482,7 @@ void srs_update_proc_stat()
|
|||
// @see https://github.com/simple-rtmp-server/srs/issues/397
|
||||
static int user_hz = 0;
|
||||
if (user_hz <= 0) {
|
||||
user_hz = sysconf(_SC_CLK_TCK);
|
||||
user_hz = (int)sysconf(_SC_CLK_TCK);
|
||||
srs_trace("USER_HZ=%d", user_hz);
|
||||
srs_assert(user_hz > 0);
|
||||
}
|
||||
|
@ -646,12 +706,12 @@ void srs_update_disk_stat()
|
|||
|
||||
if (o.pgpgin > 0 && r.pgpgin > o.pgpgin && duration_ms > 0) {
|
||||
// KBps = KB * 1000 / ms = KB/s
|
||||
r.in_KBps = (r.pgpgin - o.pgpgin) * 1000 / duration_ms;
|
||||
r.in_KBps = (int)((r.pgpgin - o.pgpgin) * 1000 / duration_ms);
|
||||
}
|
||||
|
||||
if (o.pgpgout > 0 && r.pgpgout > o.pgpgout && duration_ms > 0) {
|
||||
// KBps = KB * 1000 / ms = KB/s
|
||||
r.out_KBps = (r.pgpgout - o.pgpgout) * 1000 / duration_ms;
|
||||
r.out_KBps = (int)((r.pgpgout - o.pgpgout) * 1000 / duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,8 +831,8 @@ SrsCpuInfo* srs_get_cpuinfo()
|
|||
// initialize cpu info.
|
||||
cpu = new SrsCpuInfo();
|
||||
cpu->ok = true;
|
||||
cpu->nb_processors = sysconf(_SC_NPROCESSORS_CONF);
|
||||
cpu->nb_processors_online = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
cpu->nb_processors = (int)sysconf(_SC_NPROCESSORS_CONF);
|
||||
cpu->nb_processors_online = (int)sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,14 @@ extern std::string srs_path_build_timestamp(std::string template_path);
|
|||
extern void srs_parse_endpoint(std::string ip_port, std::string& ip, std::string& port);
|
||||
extern void srs_parse_endpoint(std::string ip_port, std::string& ip, int& port);
|
||||
|
||||
/**
|
||||
* kill the pid by SIGINT, then wait to quit,
|
||||
* kill the pid by SIGKILL again when exceed the timeout.
|
||||
* @param pid the pid to kill. ignore for -1. set to -1 when killed.
|
||||
* @return an int error code.
|
||||
*/
|
||||
extern int srs_kill_forced(int& pid);
|
||||
|
||||
// current process resouce usage.
|
||||
// @see: man getrusage
|
||||
class SrsRusage
|
||||
|
|
|
@ -96,6 +96,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define ERROR_SYSTEM_TIME 1055
|
||||
#define ERROR_SYSTEM_DIR_EXISTS 1056
|
||||
#define ERROR_SYSTEM_CREATE_DIR 1057
|
||||
#define ERROR_SYSTEM_KILL 1058
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// RTMP protocol error.
|
||||
|
|
Loading…
Reference in a new issue