mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 03:41:55 +00:00
refine the thread to three category.
This commit is contained in:
parent
2f0ef87d6d
commit
e5f449ce36
25 changed files with 648 additions and 416 deletions
|
@ -41,12 +41,11 @@ ISrsAsyncCallTask::~ISrsAsyncCallTask()
|
||||||
|
|
||||||
SrsAsyncCallWorker::SrsAsyncCallWorker()
|
SrsAsyncCallWorker::SrsAsyncCallWorker()
|
||||||
{
|
{
|
||||||
pthread = new SrsThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US, true);
|
pthread = new SrsReusableThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsAsyncCallWorker::~SrsAsyncCallWorker()
|
SrsAsyncCallWorker::~SrsAsyncCallWorker()
|
||||||
{
|
{
|
||||||
stop();
|
|
||||||
srs_freep(pthread);
|
srs_freep(pthread);
|
||||||
|
|
||||||
std::vector<ISrsAsyncCallTask*>::iterator it;
|
std::vector<ISrsAsyncCallTask*>::iterator it;
|
||||||
|
|
|
@ -57,10 +57,10 @@ public:
|
||||||
* when worker call with the task, the worker will do it in isolate thread.
|
* when worker call with the task, the worker will do it in isolate thread.
|
||||||
* that is, the task is execute/call in async mode.
|
* that is, the task is execute/call in async mode.
|
||||||
*/
|
*/
|
||||||
class SrsAsyncCallWorker : public ISrsThreadHandler
|
class SrsAsyncCallWorker : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
std::vector<ISrsAsyncCallTask*> tasks;
|
std::vector<ISrsAsyncCallTask*> tasks;
|
||||||
public:
|
public:
|
||||||
SrsAsyncCallWorker();
|
SrsAsyncCallWorker();
|
||||||
|
@ -70,6 +70,8 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual int start();
|
virtual int start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
|
// interface ISrsReusableThreadHandler
|
||||||
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,12 +45,17 @@ SrsConnection::SrsConnection(IConnectionManager* cm, st_netfd_t c)
|
||||||
// so we never use joinable.
|
// so we never use joinable.
|
||||||
// TODO: FIXME: maybe other thread need to stop it.
|
// TODO: FIXME: maybe other thread need to stop it.
|
||||||
// @see: https://github.com/simple-rtmp-server/srs/issues/78
|
// @see: https://github.com/simple-rtmp-server/srs/issues/78
|
||||||
pthread = new SrsThread("conn", this, 0, false);
|
pthread = new SrsOneCycleThread("conn", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsConnection::~SrsConnection()
|
SrsConnection::~SrsConnection()
|
||||||
{
|
{
|
||||||
stop();
|
/**
|
||||||
|
* when delete the connection, stop the connection,
|
||||||
|
* close the underlayer socket, delete the thread.
|
||||||
|
*/
|
||||||
|
srs_close_stfd(stfd);
|
||||||
|
srs_freep(pthread);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsConnection::start()
|
int SrsConnection::start()
|
||||||
|
@ -83,9 +88,6 @@ int SrsConnection::cycle()
|
||||||
if (ret == ERROR_SOCKET_CLOSED) {
|
if (ret == ERROR_SOCKET_CLOSED) {
|
||||||
srs_warn("client disconnect peer. ret=%d", ret);
|
srs_warn("client disconnect peer. ret=%d", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set loop to stop to quit.
|
|
||||||
pthread->stop_loop();
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -101,10 +103,4 @@ int SrsConnection::srs_id()
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsConnection::stop()
|
|
||||||
{
|
|
||||||
srs_close_stfd(stfd);
|
|
||||||
srs_freep(pthread);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,14 +58,14 @@ public:
|
||||||
* all connections accept from listener must extends from this base class,
|
* all connections accept from listener must extends from this base class,
|
||||||
* server will add the connection to manager, and delete it when remove.
|
* server will add the connection to manager, and delete it when remove.
|
||||||
*/
|
*/
|
||||||
class SrsConnection : public virtual ISrsThreadHandler, public virtual IKbpsDelta
|
class SrsConnection : public virtual ISrsOneCycleThreadHandler, public virtual IKbpsDelta
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* each connection start a green thread,
|
* each connection start a green thread,
|
||||||
* when thread stop, the connection will be delete by server.
|
* when thread stop, the connection will be delete by server.
|
||||||
*/
|
*/
|
||||||
SrsThread* pthread;
|
SrsOneCycleThread* pthread;
|
||||||
/**
|
/**
|
||||||
* the id of connection.
|
* the id of connection.
|
||||||
*/
|
*/
|
||||||
|
@ -97,6 +97,8 @@ public:
|
||||||
* to remove the client by server->remove(this).
|
* to remove the client by server->remove(this).
|
||||||
*/
|
*/
|
||||||
virtual int start();
|
virtual int start();
|
||||||
|
// interface ISrsOneCycleThreadHandler
|
||||||
|
public:
|
||||||
/**
|
/**
|
||||||
* the thread cycle function,
|
* the thread cycle function,
|
||||||
* when serve connection completed, terminate the loop which will terminate the thread,
|
* when serve connection completed, terminate the loop which will terminate the thread,
|
||||||
|
@ -119,12 +121,6 @@ protected:
|
||||||
* for concrete connection to do the cycle.
|
* for concrete connection to do the cycle.
|
||||||
*/
|
*/
|
||||||
virtual int do_cycle() = 0;
|
virtual int do_cycle() = 0;
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* when delete the connection, stop the connection,
|
|
||||||
* close the underlayer socket, delete the thread.
|
|
||||||
*/
|
|
||||||
virtual void stop();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,7 +70,7 @@ SrsEdgeIngester::SrsEdgeIngester()
|
||||||
origin_index = 0;
|
origin_index = 0;
|
||||||
stream_id = 0;
|
stream_id = 0;
|
||||||
stfd = NULL;
|
stfd = NULL;
|
||||||
pthread = new SrsThread("edge-igs", this, SRS_EDGE_INGESTER_SLEEP_US, true);
|
pthread = new SrsReusableThread("edge-igs", this, SRS_EDGE_INGESTER_SLEEP_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsEdgeIngester::~SrsEdgeIngester()
|
SrsEdgeIngester::~SrsEdgeIngester()
|
||||||
|
@ -171,7 +171,7 @@ int SrsEdgeIngester::ingest()
|
||||||
SrsPithyPrint* pprint = SrsPithyPrint::create_edge();
|
SrsPithyPrint* pprint = SrsPithyPrint::create_edge();
|
||||||
SrsAutoFree(SrsPithyPrint, pprint);
|
SrsAutoFree(SrsPithyPrint, pprint);
|
||||||
|
|
||||||
while (pthread->can_loop()) {
|
while (!pthread->interrupted()) {
|
||||||
pprint->elapse();
|
pprint->elapse();
|
||||||
|
|
||||||
// pithy print
|
// pithy print
|
||||||
|
@ -397,7 +397,7 @@ SrsEdgeForwarder::SrsEdgeForwarder()
|
||||||
origin_index = 0;
|
origin_index = 0;
|
||||||
stream_id = 0;
|
stream_id = 0;
|
||||||
stfd = NULL;
|
stfd = NULL;
|
||||||
pthread = new SrsThread("edge-fwr", this, SRS_EDGE_FORWARDER_SLEEP_US, true);
|
pthread = new SrsReusableThread("edge-fwr", this, SRS_EDGE_FORWARDER_SLEEP_US);
|
||||||
queue = new SrsMessageQueue();
|
queue = new SrsMessageQueue();
|
||||||
send_error_code = ERROR_SUCCESS;
|
send_error_code = ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ int SrsEdgeForwarder::cycle()
|
||||||
|
|
||||||
SrsMessageArray msgs(SYS_MAX_EDGE_SEND_MSGS);
|
SrsMessageArray msgs(SYS_MAX_EDGE_SEND_MSGS);
|
||||||
|
|
||||||
while (pthread->can_loop()) {
|
while (!pthread->interrupted()) {
|
||||||
if (send_error_code != ERROR_SUCCESS) {
|
if (send_error_code != ERROR_SUCCESS) {
|
||||||
st_usleep(SRS_EDGE_FORWARDER_ERROR_US);
|
st_usleep(SRS_EDGE_FORWARDER_ERROR_US);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -75,7 +75,7 @@ enum SrsEdgeUserState
|
||||||
/**
|
/**
|
||||||
* edge used to ingest stream from origin.
|
* edge used to ingest stream from origin.
|
||||||
*/
|
*/
|
||||||
class SrsEdgeIngester : public ISrsThreadHandler
|
class SrsEdgeIngester : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int stream_id;
|
int stream_id;
|
||||||
|
@ -83,7 +83,7 @@ private:
|
||||||
SrsSource* _source;
|
SrsSource* _source;
|
||||||
SrsPlayEdge* _edge;
|
SrsPlayEdge* _edge;
|
||||||
SrsRequest* _req;
|
SrsRequest* _req;
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
st_netfd_t stfd;
|
st_netfd_t stfd;
|
||||||
ISrsProtocolReaderWriter* io;
|
ISrsProtocolReaderWriter* io;
|
||||||
SrsKbps* kbps;
|
SrsKbps* kbps;
|
||||||
|
@ -96,7 +96,7 @@ public:
|
||||||
virtual int initialize(SrsSource* source, SrsPlayEdge* edge, SrsRequest* req);
|
virtual int initialize(SrsSource* source, SrsPlayEdge* edge, SrsRequest* req);
|
||||||
virtual int start();
|
virtual int start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
// interface ISrsThreadHandler
|
// interface ISrsReusableThreadHandler
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
private:
|
private:
|
||||||
|
@ -110,7 +110,7 @@ private:
|
||||||
/**
|
/**
|
||||||
* edge used to forward stream to origin.
|
* edge used to forward stream to origin.
|
||||||
*/
|
*/
|
||||||
class SrsEdgeForwarder : public ISrsThreadHandler
|
class SrsEdgeForwarder : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int stream_id;
|
int stream_id;
|
||||||
|
@ -118,7 +118,7 @@ private:
|
||||||
SrsSource* _source;
|
SrsSource* _source;
|
||||||
SrsPublishEdge* _edge;
|
SrsPublishEdge* _edge;
|
||||||
SrsRequest* _req;
|
SrsRequest* _req;
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
st_netfd_t stfd;
|
st_netfd_t stfd;
|
||||||
ISrsProtocolReaderWriter* io;
|
ISrsProtocolReaderWriter* io;
|
||||||
SrsKbps* kbps;
|
SrsKbps* kbps;
|
||||||
|
@ -144,7 +144,7 @@ public:
|
||||||
virtual int initialize(SrsSource* source, SrsPublishEdge* edge, SrsRequest* req);
|
virtual int initialize(SrsSource* source, SrsPublishEdge* edge, SrsRequest* req);
|
||||||
virtual int start();
|
virtual int start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
// interface ISrsThreadHandler
|
// interface ISrsReusableThreadHandler
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -44,7 +44,7 @@ static std::vector<std::string> _transcoded_url;
|
||||||
|
|
||||||
SrsEncoder::SrsEncoder()
|
SrsEncoder::SrsEncoder()
|
||||||
{
|
{
|
||||||
pthread = new SrsThread("encoder", this, SRS_RTMP_ENCODER_SLEEP_US, true);
|
pthread = new SrsReusableThread("encoder", this, SRS_RTMP_ENCODER_SLEEP_US);
|
||||||
pprint = SrsPithyPrint::create_encoder();
|
pprint = SrsPithyPrint::create_encoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,13 +45,13 @@ class SrsFFMPEG;
|
||||||
* the encoder for a stream,
|
* the encoder for a stream,
|
||||||
* may use multiple ffmpegs to transcode the specified stream.
|
* may use multiple ffmpegs to transcode the specified stream.
|
||||||
*/
|
*/
|
||||||
class SrsEncoder : public ISrsThreadHandler
|
class SrsEncoder : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string input_stream_name;
|
std::string input_stream_name;
|
||||||
std::vector<SrsFFMPEG*> ffmpegs;
|
std::vector<SrsFFMPEG*> ffmpegs;
|
||||||
private:
|
private:
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
SrsPithyPrint* pprint;
|
SrsPithyPrint* pprint;
|
||||||
public:
|
public:
|
||||||
SrsEncoder();
|
SrsEncoder();
|
||||||
|
@ -59,7 +59,7 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual int on_publish(SrsRequest* req);
|
virtual int on_publish(SrsRequest* req);
|
||||||
virtual void on_unpublish();
|
virtual void on_unpublish();
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsReusableThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
virtual void on_thread_stop();
|
virtual void on_thread_stop();
|
||||||
|
|
|
@ -59,7 +59,7 @@ SrsForwarder::SrsForwarder(SrsSource* _source)
|
||||||
kbps = new SrsKbps();
|
kbps = new SrsKbps();
|
||||||
stream_id = 0;
|
stream_id = 0;
|
||||||
|
|
||||||
pthread = new SrsThread("forward", this, SRS_FORWARDER_SLEEP_US, true);
|
pthread = new SrsReusableThread("forward", this, SRS_FORWARDER_SLEEP_US);
|
||||||
queue = new SrsMessageQueue();
|
queue = new SrsMessageQueue();
|
||||||
jitter = new SrsRtmpJitter();
|
jitter = new SrsRtmpJitter();
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ int SrsForwarder::forward()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pthread->can_loop()) {
|
while (!pthread->interrupted()) {
|
||||||
pprint->elapse();
|
pprint->elapse();
|
||||||
|
|
||||||
// read from client.
|
// read from client.
|
||||||
|
|
|
@ -48,7 +48,7 @@ class SrsKbps;
|
||||||
* forward the stream to other servers.
|
* forward the stream to other servers.
|
||||||
*/
|
*/
|
||||||
// TODO: FIXME: refine the error log, comments it.
|
// TODO: FIXME: refine the error log, comments it.
|
||||||
class SrsForwarder : public ISrsThreadHandler
|
class SrsForwarder : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// the ep to forward, server[:port].
|
// the ep to forward, server[:port].
|
||||||
|
@ -57,7 +57,7 @@ private:
|
||||||
int stream_id;
|
int stream_id;
|
||||||
private:
|
private:
|
||||||
st_netfd_t stfd;
|
st_netfd_t stfd;
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
private:
|
private:
|
||||||
SrsSource* source;
|
SrsSource* source;
|
||||||
ISrsProtocolReaderWriter* io;
|
ISrsProtocolReaderWriter* io;
|
||||||
|
@ -95,7 +95,7 @@ public:
|
||||||
* @param shared_video, directly ptr, copy it if need to save it.
|
* @param shared_video, directly ptr, copy it if need to save it.
|
||||||
*/
|
*/
|
||||||
virtual int on_video(SrsSharedPtrMessage* shared_video);
|
virtual int on_video(SrsSharedPtrMessage* shared_video);
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsReusableThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1157,12 +1157,11 @@ SrsStreamCache::SrsStreamCache(SrsSource* s, SrsRequest* r)
|
||||||
req = r->copy();
|
req = r->copy();
|
||||||
source = s;
|
source = s;
|
||||||
queue = new SrsMessageQueue(true);
|
queue = new SrsMessageQueue(true);
|
||||||
pthread = new SrsThread("http-stream", this, 0, false);
|
pthread = new SrsEndlessThread("http-stream", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStreamCache::~SrsStreamCache()
|
SrsStreamCache::~SrsStreamCache()
|
||||||
{
|
{
|
||||||
pthread->stop();
|
|
||||||
srs_freep(pthread);
|
srs_freep(pthread);
|
||||||
|
|
||||||
srs_freep(queue);
|
srs_freep(queue);
|
||||||
|
|
|
@ -386,20 +386,20 @@ protected:
|
||||||
* for example, the audio stream cache to make android(weixin) happy.
|
* for example, the audio stream cache to make android(weixin) happy.
|
||||||
* we start a thread to shrink the queue.
|
* we start a thread to shrink the queue.
|
||||||
*/
|
*/
|
||||||
class SrsStreamCache : public ISrsThreadHandler
|
class SrsStreamCache : public ISrsEndlessThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsMessageQueue* queue;
|
SrsMessageQueue* queue;
|
||||||
SrsSource* source;
|
SrsSource* source;
|
||||||
SrsRequest* req;
|
SrsRequest* req;
|
||||||
SrsThread* pthread;
|
SrsEndlessThread* pthread;
|
||||||
public:
|
public:
|
||||||
SrsStreamCache(SrsSource* s, SrsRequest* r);
|
SrsStreamCache(SrsSource* s, SrsRequest* r);
|
||||||
virtual ~SrsStreamCache();
|
virtual ~SrsStreamCache();
|
||||||
public:
|
public:
|
||||||
virtual int start();
|
virtual int start();
|
||||||
virtual int dump_cache(SrsConsumer* consumer);
|
virtual int dump_cache(SrsConsumer* consumer);
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsEndlessThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
};
|
};
|
||||||
|
@ -669,7 +669,7 @@ public:
|
||||||
virtual int hls_update_m3u8(SrsRequest* r, std::string m3u8);
|
virtual int hls_update_m3u8(SrsRequest* r, std::string m3u8);
|
||||||
virtual int hls_update_ts(SrsRequest* r, std::string uri, std::string ts);
|
virtual int hls_update_ts(SrsRequest* r, std::string uri, std::string ts);
|
||||||
virtual void unmount_hls(SrsRequest* r);
|
virtual void unmount_hls(SrsRequest* r);
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsReloadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int on_reload_vhost_http_updated();
|
virtual int on_reload_vhost_http_updated();
|
||||||
virtual int on_reload_vhost_http_remux_updated();
|
virtual int on_reload_vhost_http_remux_updated();
|
||||||
|
|
|
@ -55,7 +55,7 @@ SrsIngester::SrsIngester()
|
||||||
{
|
{
|
||||||
_srs_config->subscribe(this);
|
_srs_config->subscribe(this);
|
||||||
|
|
||||||
pthread = new SrsThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US, true);
|
pthread = new SrsReusableThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US);
|
||||||
pprint = SrsPithyPrint::create_ingester();
|
pprint = SrsPithyPrint::create_ingester();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,12 +59,12 @@ public:
|
||||||
* encode with FFMPEG(optional),
|
* encode with FFMPEG(optional),
|
||||||
* push to SRS(or any RTMP server) over RTMP.
|
* push to SRS(or any RTMP server) over RTMP.
|
||||||
*/
|
*/
|
||||||
class SrsIngester : public ISrsThreadHandler, public ISrsReloadHandler
|
class SrsIngester : public ISrsReusableThreadHandler, public ISrsReloadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<SrsIngesterFFMPEG*> ingesters;
|
std::vector<SrsIngesterFFMPEG*> ingesters;
|
||||||
private:
|
private:
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
SrsPithyPrint* pprint;
|
SrsPithyPrint* pprint;
|
||||||
public:
|
public:
|
||||||
SrsIngester();
|
SrsIngester();
|
||||||
|
@ -72,7 +72,7 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual int start();
|
virtual int start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsReusableThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
virtual void on_thread_stop();
|
virtual void on_thread_stop();
|
||||||
|
|
|
@ -79,7 +79,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p)
|
||||||
nb_buf = SRS_UDP_MAX_PACKET_SIZE;
|
nb_buf = SRS_UDP_MAX_PACKET_SIZE;
|
||||||
buf = new char[nb_buf];
|
buf = new char[nb_buf];
|
||||||
|
|
||||||
pthread = new SrsThread("udp", this, 0, true);
|
pthread = new SrsReusableThread("udp", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsUdpListener::~SrsUdpListener()
|
SrsUdpListener::~SrsUdpListener()
|
||||||
|
@ -157,7 +157,7 @@ int SrsUdpListener::cycle()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
while (pthread->can_loop()) {
|
while (!pthread->interrupted()) {
|
||||||
// TODO: FIXME: support ipv6, @see man 7 ipv6
|
// TODO: FIXME: support ipv6, @see man 7 ipv6
|
||||||
sockaddr_in from;
|
sockaddr_in from;
|
||||||
int nb_from = sizeof(sockaddr_in);
|
int nb_from = sizeof(sockaddr_in);
|
||||||
|
@ -190,7 +190,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)
|
||||||
_fd = -1;
|
_fd = -1;
|
||||||
_stfd = NULL;
|
_stfd = NULL;
|
||||||
|
|
||||||
pthread = new SrsThread("tcp", this, 0, true);
|
pthread = new SrsReusableThread("tcp", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTcpListener::~SrsTcpListener()
|
SrsTcpListener::~SrsTcpListener()
|
||||||
|
|
|
@ -82,12 +82,12 @@ public:
|
||||||
/**
|
/**
|
||||||
* bind udp port, start thread to recv packet and handler it.
|
* bind udp port, start thread to recv packet and handler it.
|
||||||
*/
|
*/
|
||||||
class SrsUdpListener : public ISrsThreadHandler
|
class SrsUdpListener : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int _fd;
|
int _fd;
|
||||||
st_netfd_t _stfd;
|
st_netfd_t _stfd;
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
private:
|
private:
|
||||||
char* buf;
|
char* buf;
|
||||||
int nb_buf;
|
int nb_buf;
|
||||||
|
@ -103,7 +103,7 @@ public:
|
||||||
virtual st_netfd_t stfd();
|
virtual st_netfd_t stfd();
|
||||||
public:
|
public:
|
||||||
virtual int listen();
|
virtual int listen();
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsReusableThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
};
|
};
|
||||||
|
@ -111,12 +111,12 @@ public:
|
||||||
/**
|
/**
|
||||||
* bind and listen tcp port, use handler to process the client.
|
* bind and listen tcp port, use handler to process the client.
|
||||||
*/
|
*/
|
||||||
class SrsTcpListener : public ISrsThreadHandler
|
class SrsTcpListener : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int _fd;
|
int _fd;
|
||||||
st_netfd_t _stfd;
|
st_netfd_t _stfd;
|
||||||
SrsThread* pthread;
|
SrsReusableThread* pthread;
|
||||||
private:
|
private:
|
||||||
ISrsTcpHandler* handler;
|
ISrsTcpHandler* handler;
|
||||||
std::string ip;
|
std::string ip;
|
||||||
|
@ -128,7 +128,7 @@ public:
|
||||||
virtual int fd();
|
virtual int fd();
|
||||||
public:
|
public:
|
||||||
virtual int listen();
|
virtual int listen();
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsReusableThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
};
|
};
|
||||||
|
|
|
@ -82,7 +82,7 @@ public:
|
||||||
virtual void trace(const char* tag, int context_id, const char* fmt, ...);
|
virtual void trace(const char* tag, int context_id, const char* fmt, ...);
|
||||||
virtual void warn(const char* tag, int context_id, const char* fmt, ...);
|
virtual void warn(const char* tag, int context_id, const char* fmt, ...);
|
||||||
virtual void error(const char* tag, int context_id, const char* fmt, ...);
|
virtual void error(const char* tag, int context_id, const char* fmt, ...);
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsReloadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int on_reload_log_tank();
|
virtual int on_reload_log_tank();
|
||||||
virtual int on_reload_log_level();
|
virtual int on_reload_log_level();
|
||||||
|
|
|
@ -50,7 +50,7 @@ SrsRecvThread::SrsRecvThread(ISrsMessageHandler* msg_handler, SrsRtmpServer* rtm
|
||||||
timeout = timeout_ms;
|
timeout = timeout_ms;
|
||||||
handler = msg_handler;
|
handler = msg_handler;
|
||||||
rtmp = rtmp_sdk;
|
rtmp = rtmp_sdk;
|
||||||
trd = new SrsThread("recv", this, 0, true);
|
trd = new SrsReusableThread("recv", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRecvThread::~SrsRecvThread()
|
SrsRecvThread::~SrsRecvThread()
|
||||||
|
@ -76,7 +76,7 @@ int SrsRecvThread::cycle()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
while (trd->can_loop()) {
|
while (!trd->interrupted()) {
|
||||||
if (!handler->can_handle()) {
|
if (!handler->can_handle()) {
|
||||||
st_usleep(timeout * 1000);
|
st_usleep(timeout * 1000);
|
||||||
continue;
|
continue;
|
||||||
|
@ -96,7 +96,7 @@ int SrsRecvThread::cycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use no timeout to recv, should never got any error.
|
// we use no timeout to recv, should never got any error.
|
||||||
trd->stop_loop();
|
trd->interrupt();
|
||||||
|
|
||||||
// notice the handler got a recv error.
|
// notice the handler got a recv error.
|
||||||
handler->on_recv_error(ret);
|
handler->on_recv_error(ret);
|
||||||
|
@ -111,7 +111,7 @@ int SrsRecvThread::cycle()
|
||||||
|
|
||||||
void SrsRecvThread::stop_loop()
|
void SrsRecvThread::stop_loop()
|
||||||
{
|
{
|
||||||
trd->stop_loop();
|
trd->interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsRecvThread::on_thread_start()
|
void SrsRecvThread::on_thread_start()
|
||||||
|
|
|
@ -79,10 +79,10 @@ public:
|
||||||
/**
|
/**
|
||||||
* the recv thread, use message handler to handle each received message.
|
* the recv thread, use message handler to handle each received message.
|
||||||
*/
|
*/
|
||||||
class SrsRecvThread : public ISrsThreadHandler
|
class SrsRecvThread : public ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
SrsThread* trd;
|
SrsReusableThread* trd;
|
||||||
ISrsMessageHandler* handler;
|
ISrsMessageHandler* handler;
|
||||||
SrsRtmpServer* rtmp;
|
SrsRtmpServer* rtmp;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
|
@ -192,7 +192,7 @@ SrsRtspConn::SrsRtspConn(SrsRtspCaster* c, st_netfd_t fd, std::string o)
|
||||||
stfd = fd;
|
stfd = fd;
|
||||||
skt = new SrsStSocket(fd);
|
skt = new SrsStSocket(fd);
|
||||||
rtsp = new SrsRtspStack(skt);
|
rtsp = new SrsRtspStack(skt);
|
||||||
trd = new SrsThread("rtsp", this, 0, false);
|
trd = new SrsOneCycleThread("rtsp", this);
|
||||||
|
|
||||||
req = NULL;
|
req = NULL;
|
||||||
io = NULL;
|
io = NULL;
|
||||||
|
@ -210,7 +210,6 @@ SrsRtspConn::SrsRtspConn(SrsRtspCaster* c, st_netfd_t fd, std::string o)
|
||||||
SrsRtspConn::~SrsRtspConn()
|
SrsRtspConn::~SrsRtspConn()
|
||||||
{
|
{
|
||||||
srs_close_stfd(stfd);
|
srs_close_stfd(stfd);
|
||||||
trd->stop();
|
|
||||||
|
|
||||||
srs_freep(video_rtp);
|
srs_freep(video_rtp);
|
||||||
srs_freep(audio_rtp);
|
srs_freep(audio_rtp);
|
||||||
|
@ -219,7 +218,9 @@ SrsRtspConn::~SrsRtspConn()
|
||||||
srs_freep(skt);
|
srs_freep(skt);
|
||||||
srs_freep(rtsp);
|
srs_freep(rtsp);
|
||||||
|
|
||||||
close();
|
srs_freep(client);
|
||||||
|
srs_freep(io);
|
||||||
|
srs_freep(req);
|
||||||
|
|
||||||
srs_freep(vjitter);
|
srs_freep(vjitter);
|
||||||
srs_freep(ajitter);
|
srs_freep(ajitter);
|
||||||
|
@ -412,9 +413,6 @@ int SrsRtspConn::cycle()
|
||||||
srs_warn("client disconnect peer. ret=%d", ret);
|
srs_warn("client disconnect peer. ret=%d", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// terminate thread in the thread cycle itself.
|
|
||||||
trd->stop_loop();
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,14 +761,6 @@ int SrsRtspConn::connect_app(string ep_server, string ep_port)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsRtspConn::close()
|
|
||||||
{
|
|
||||||
srs_freep(client);
|
|
||||||
srs_freep(io);
|
|
||||||
srs_freep(req);
|
|
||||||
srs_close_stfd(stfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsRtspCaster::SrsRtspCaster(SrsConfDirective* c)
|
SrsRtspCaster::SrsRtspCaster(SrsConfDirective* c)
|
||||||
{
|
{
|
||||||
// TODO: FIXME: support reload.
|
// TODO: FIXME: support reload.
|
||||||
|
|
|
@ -113,7 +113,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* the rtsp connection serve the fd.
|
* the rtsp connection serve the fd.
|
||||||
*/
|
*/
|
||||||
class SrsRtspConn : public ISrsThreadHandler
|
class SrsRtspConn : public ISrsOneCycleThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string output_template;
|
std::string output_template;
|
||||||
|
@ -136,7 +136,7 @@ private:
|
||||||
SrsStSocket* skt;
|
SrsStSocket* skt;
|
||||||
SrsRtspStack* rtsp;
|
SrsRtspStack* rtsp;
|
||||||
SrsRtspCaster* caster;
|
SrsRtspCaster* caster;
|
||||||
SrsThread* trd;
|
SrsOneCycleThread* trd;
|
||||||
private:
|
private:
|
||||||
SrsRequest* req;
|
SrsRequest* req;
|
||||||
SrsStSocket* io;
|
SrsStSocket* io;
|
||||||
|
@ -163,7 +163,7 @@ private:
|
||||||
// internal methods
|
// internal methods
|
||||||
public:
|
public:
|
||||||
virtual int on_rtp_packet(SrsRtpPacket* pkt, int stream_id);
|
virtual int on_rtp_packet(SrsRtpPacket* pkt, int stream_id);
|
||||||
// interface ISrsThreadHandler
|
// interface ISrsOneCycleThreadHandler
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
virtual void on_thread_stop();
|
virtual void on_thread_stop();
|
||||||
|
@ -182,8 +182,6 @@ private:
|
||||||
// @remark ignore when not connected, reconnect when disconnected.
|
// @remark ignore when not connected, reconnect when disconnected.
|
||||||
virtual int connect();
|
virtual int connect();
|
||||||
virtual int connect_app(std::string ep_server, std::string ep_port);
|
virtual int connect_app(std::string ep_server, std::string ep_port);
|
||||||
// close the connected io and rtmp to ready to be re-connect.
|
|
||||||
virtual void close();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -367,13 +367,12 @@ SrsSignalManager::SrsSignalManager(SrsServer* server)
|
||||||
|
|
||||||
_server = server;
|
_server = server;
|
||||||
sig_pipe[0] = sig_pipe[1] = -1;
|
sig_pipe[0] = sig_pipe[1] = -1;
|
||||||
pthread = new SrsThread("signal", this, 0, true);
|
pthread = new SrsEndlessThread("signal", this);
|
||||||
signal_read_stfd = NULL;
|
signal_read_stfd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsSignalManager::~SrsSignalManager()
|
SrsSignalManager::~SrsSignalManager()
|
||||||
{
|
{
|
||||||
pthread->stop();
|
|
||||||
srs_freep(pthread);
|
srs_freep(pthread);
|
||||||
|
|
||||||
srs_close_stfd(signal_read_stfd);
|
srs_close_stfd(signal_read_stfd);
|
||||||
|
|
|
@ -179,7 +179,7 @@ public:
|
||||||
* convert signal to io,
|
* convert signal to io,
|
||||||
* @see: st-1.9/docs/notes.html
|
* @see: st-1.9/docs/notes.html
|
||||||
*/
|
*/
|
||||||
class SrsSignalManager : public ISrsThreadHandler
|
class SrsSignalManager : public ISrsEndlessThreadHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/* Per-process pipe which is used as a signal queue. */
|
/* Per-process pipe which is used as a signal queue. */
|
||||||
|
@ -188,14 +188,14 @@ private:
|
||||||
st_netfd_t signal_read_stfd;
|
st_netfd_t signal_read_stfd;
|
||||||
private:
|
private:
|
||||||
SrsServer* _server;
|
SrsServer* _server;
|
||||||
SrsThread* pthread;
|
SrsEndlessThread* pthread;
|
||||||
public:
|
public:
|
||||||
SrsSignalManager(SrsServer* server);
|
SrsSignalManager(SrsServer* server);
|
||||||
virtual ~SrsSignalManager();
|
virtual ~SrsSignalManager();
|
||||||
public:
|
public:
|
||||||
virtual int initialize();
|
virtual int initialize();
|
||||||
virtual int start();
|
virtual int start();
|
||||||
// interface ISrsThreadHandler.
|
// interface ISrsEndlessThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual int cycle();
|
virtual int cycle();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -26,206 +26,337 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <srs_kernel_error.hpp>
|
#include <srs_kernel_error.hpp>
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
|
|
||||||
ISrsThreadHandler::ISrsThreadHandler()
|
namespace internal {
|
||||||
{
|
ISrsThreadHandler::ISrsThreadHandler()
|
||||||
}
|
{
|
||||||
|
}
|
||||||
ISrsThreadHandler::~ISrsThreadHandler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ISrsThreadHandler::on_thread_start()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int ISrsThreadHandler::on_before_cycle()
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ISrsThreadHandler::on_end_cycle()
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ISrsThreadHandler::on_thread_stop()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsThread::SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
handler = thread_handler;
|
|
||||||
cycle_interval_us = interval_us;
|
|
||||||
|
|
||||||
tid = NULL;
|
ISrsThreadHandler::~ISrsThreadHandler()
|
||||||
loop = false;
|
{
|
||||||
really_terminated = true;
|
}
|
||||||
_cid = -1;
|
|
||||||
_joinable = joinable;
|
|
||||||
|
|
||||||
// in start(), the thread cycle method maybe stop and remove the thread itself,
|
void ISrsThreadHandler::on_thread_start()
|
||||||
// and the thread start() is waiting for the _cid, and segment fault then.
|
{
|
||||||
// @see https://github.com/simple-rtmp-server/srs/issues/110
|
}
|
||||||
// thread will set _cid, callback on_thread_start(), then wait for the can_run signal.
|
|
||||||
can_run = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsThread::~SrsThread()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsThread::cid()
|
|
||||||
{
|
|
||||||
return _cid;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsThread::start()
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
if(tid) {
|
int ISrsThreadHandler::on_before_cycle()
|
||||||
srs_info("thread %s already running.", _name);
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){
|
int ISrsThreadHandler::on_end_cycle()
|
||||||
ret = ERROR_ST_CREATE_CYCLE_THREAD;
|
{
|
||||||
srs_error("st_thread_create failed. ret=%d", ret);
|
int ret = ERROR_SUCCESS;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we set to loop to true for thread to run.
|
void ISrsThreadHandler::on_thread_stop()
|
||||||
loop = true;
|
{
|
||||||
|
|
||||||
// wait for cid to ready, for parent thread to get the cid.
|
|
||||||
while (_cid < 0 && loop) {
|
|
||||||
st_usleep(10 * 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now, cycle thread can run.
|
SrsThread::SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable)
|
||||||
can_run = true;
|
{
|
||||||
|
_name = name;
|
||||||
return ret;
|
handler = thread_handler;
|
||||||
}
|
cycle_interval_us = interval_us;
|
||||||
|
|
||||||
void SrsThread::stop()
|
|
||||||
{
|
|
||||||
if (tid) {
|
|
||||||
loop = false;
|
|
||||||
|
|
||||||
// the interrupt will cause the socket to read/write error,
|
|
||||||
// which will terminate the cycle thread.
|
|
||||||
st_thread_interrupt(tid);
|
|
||||||
|
|
||||||
// when joinable, wait util quit.
|
|
||||||
if (_joinable) {
|
|
||||||
// wait the thread to exit.
|
|
||||||
int ret = st_thread_join(tid, NULL);
|
|
||||||
if (ret) {
|
|
||||||
srs_warn("core: ignore join thread failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait the thread actually terminated.
|
|
||||||
// sometimes the thread join return -1, for example,
|
|
||||||
// when thread use st_recvfrom, the thread join return -1.
|
|
||||||
// so here, we use a variable to ensure the thread stopped.
|
|
||||||
while (!really_terminated) {
|
|
||||||
st_usleep(10 * 1000);
|
|
||||||
|
|
||||||
if (really_terminated) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
srs_warn("core: wait thread to actually terminated");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tid = NULL;
|
tid = NULL;
|
||||||
}
|
loop = false;
|
||||||
}
|
really_terminated = true;
|
||||||
|
_cid = -1;
|
||||||
bool SrsThread::can_loop()
|
_joinable = joinable;
|
||||||
{
|
|
||||||
return loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsThread::stop_loop()
|
|
||||||
{
|
|
||||||
loop = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SrsThread::thread_cycle()
|
|
||||||
{
|
|
||||||
int ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
_srs_context->generate_id();
|
|
||||||
srs_info("thread %s cycle start", _name);
|
|
||||||
|
|
||||||
_cid = _srs_context->get_id();
|
|
||||||
|
|
||||||
srs_assert(handler);
|
|
||||||
handler->on_thread_start();
|
|
||||||
|
|
||||||
// thread is running now.
|
|
||||||
really_terminated = false;
|
|
||||||
|
|
||||||
// wait for cid to ready, for parent thread to get the cid.
|
|
||||||
while (!can_run && loop) {
|
|
||||||
st_usleep(10 * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (loop) {
|
|
||||||
if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) {
|
|
||||||
srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
srs_info("thread %s on before cycle success");
|
|
||||||
|
|
||||||
if ((ret = handler->cycle()) != ERROR_SUCCESS) {
|
// in start(), the thread cycle method maybe stop and remove the thread itself,
|
||||||
if (!srs_is_client_gracefully_close(ret)) {
|
// and the thread start() is waiting for the _cid, and segment fault then.
|
||||||
srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret);
|
// @see https://github.com/simple-rtmp-server/srs/issues/110
|
||||||
|
// thread will set _cid, callback on_thread_start(), then wait for the can_run signal.
|
||||||
|
can_run = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsThread::~SrsThread()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsThread::cid()
|
||||||
|
{
|
||||||
|
return _cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsThread::start()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if(tid) {
|
||||||
|
srs_info("thread %s already running.", _name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){
|
||||||
|
ret = ERROR_ST_CREATE_CYCLE_THREAD;
|
||||||
|
srs_error("st_thread_create failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we set to loop to true for thread to run.
|
||||||
|
loop = true;
|
||||||
|
|
||||||
|
// wait for cid to ready, for parent thread to get the cid.
|
||||||
|
while (_cid < 0 && loop) {
|
||||||
|
st_usleep(10 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now, cycle thread can run.
|
||||||
|
can_run = true;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsThread::stop()
|
||||||
|
{
|
||||||
|
if (tid) {
|
||||||
|
loop = false;
|
||||||
|
|
||||||
|
// the interrupt will cause the socket to read/write error,
|
||||||
|
// which will terminate the cycle thread.
|
||||||
|
st_thread_interrupt(tid);
|
||||||
|
|
||||||
|
// when joinable, wait util quit.
|
||||||
|
if (_joinable) {
|
||||||
|
// wait the thread to exit.
|
||||||
|
int ret = st_thread_join(tid, NULL);
|
||||||
|
if (ret) {
|
||||||
|
srs_warn("core: ignore join thread failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait the thread actually terminated.
|
||||||
|
// sometimes the thread join return -1, for example,
|
||||||
|
// when thread use st_recvfrom, the thread join return -1.
|
||||||
|
// so here, we use a variable to ensure the thread stopped.
|
||||||
|
while (!really_terminated) {
|
||||||
|
st_usleep(10 * 1000);
|
||||||
|
|
||||||
|
if (really_terminated) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
srs_warn("core: wait thread to actually terminated");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto failed;
|
|
||||||
}
|
tid = NULL;
|
||||||
srs_info("thread %s cycle success", _name);
|
|
||||||
|
|
||||||
if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) {
|
|
||||||
srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
srs_info("thread %s on end cycle success", _name);
|
|
||||||
|
|
||||||
failed:
|
|
||||||
if (!loop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// to improve performance, donot sleep when interval is zero.
|
|
||||||
// @see: https://github.com/simple-rtmp-server/srs/issues/237
|
|
||||||
if (cycle_interval_us != 0) {
|
|
||||||
st_usleep(cycle_interval_us);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// readly terminated now.
|
bool SrsThread::can_loop()
|
||||||
really_terminated = true;
|
{
|
||||||
|
return loop;
|
||||||
|
}
|
||||||
|
|
||||||
handler->on_thread_stop();
|
void SrsThread::stop_loop()
|
||||||
srs_info("thread %s cycle finished", _name);
|
{
|
||||||
|
loop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsThread::thread_cycle()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
_srs_context->generate_id();
|
||||||
|
srs_info("thread %s cycle start", _name);
|
||||||
|
|
||||||
|
_cid = _srs_context->get_id();
|
||||||
|
|
||||||
|
srs_assert(handler);
|
||||||
|
handler->on_thread_start();
|
||||||
|
|
||||||
|
// thread is running now.
|
||||||
|
really_terminated = false;
|
||||||
|
|
||||||
|
// wait for cid to ready, for parent thread to get the cid.
|
||||||
|
while (!can_run && loop) {
|
||||||
|
st_usleep(10 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (loop) {
|
||||||
|
if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
srs_info("thread %s on before cycle success");
|
||||||
|
|
||||||
|
if ((ret = handler->cycle()) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||||
|
}
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
srs_info("thread %s cycle success", _name);
|
||||||
|
|
||||||
|
if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
srs_info("thread %s on end cycle success", _name);
|
||||||
|
|
||||||
|
failed:
|
||||||
|
if (!loop) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// to improve performance, donot sleep when interval is zero.
|
||||||
|
// @see: https://github.com/simple-rtmp-server/srs/issues/237
|
||||||
|
if (cycle_interval_us != 0) {
|
||||||
|
st_usleep(cycle_interval_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// readly terminated now.
|
||||||
|
really_terminated = true;
|
||||||
|
|
||||||
|
handler->on_thread_stop();
|
||||||
|
srs_info("thread %s cycle finished", _name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* SrsThread::thread_fun(void* arg)
|
||||||
|
{
|
||||||
|
SrsThread* obj = (SrsThread*)arg;
|
||||||
|
srs_assert(obj);
|
||||||
|
|
||||||
|
obj->thread_cycle();
|
||||||
|
|
||||||
|
st_thread_exit(NULL);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* SrsThread::thread_fun(void* arg)
|
ISrsEndlessThreadHandler::ISrsEndlessThreadHandler()
|
||||||
{
|
{
|
||||||
SrsThread* obj = (SrsThread*)arg;
|
|
||||||
srs_assert(obj);
|
|
||||||
|
|
||||||
obj->thread_cycle();
|
|
||||||
|
|
||||||
st_thread_exit(NULL);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsEndlessThreadHandler::~ISrsEndlessThreadHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsEndlessThread::SrsEndlessThread(const char* n, ISrsEndlessThreadHandler* h)
|
||||||
|
{
|
||||||
|
handler = h;
|
||||||
|
pthread = new internal::SrsThread(n, this, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsEndlessThread::~SrsEndlessThread()
|
||||||
|
{
|
||||||
|
pthread->stop();
|
||||||
|
srs_freep(pthread);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsEndlessThread::start()
|
||||||
|
{
|
||||||
|
return pthread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsEndlessThread::cycle()
|
||||||
|
{
|
||||||
|
return handler->cycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsOneCycleThreadHandler::ISrsOneCycleThreadHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsOneCycleThreadHandler::~ISrsOneCycleThreadHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISrsOneCycleThreadHandler::on_thread_stop()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsOneCycleThread::SrsOneCycleThread(const char* n, ISrsOneCycleThreadHandler* h)
|
||||||
|
{
|
||||||
|
handler = h;
|
||||||
|
pthread = new internal::SrsThread(n, this, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsOneCycleThread::~SrsOneCycleThread()
|
||||||
|
{
|
||||||
|
pthread->stop();
|
||||||
|
srs_freep(pthread);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsOneCycleThread::start()
|
||||||
|
{
|
||||||
|
return pthread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsOneCycleThread::cycle()
|
||||||
|
{
|
||||||
|
int ret = handler->cycle();
|
||||||
|
pthread->stop_loop();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsOneCycleThread::on_thread_stop()
|
||||||
|
{
|
||||||
|
handler->on_thread_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsReusableThreadHandler::ISrsReusableThreadHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsReusableThreadHandler::~ISrsReusableThreadHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISrsReusableThreadHandler::on_thread_stop()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsReusableThread::SrsReusableThread(const char* n, ISrsReusableThreadHandler* h, int64_t interval_us)
|
||||||
|
{
|
||||||
|
handler = h;
|
||||||
|
pthread = new internal::SrsThread(n, this, interval_us, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsReusableThread::~SrsReusableThread()
|
||||||
|
{
|
||||||
|
pthread->stop();
|
||||||
|
srs_freep(pthread);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsReusableThread::start()
|
||||||
|
{
|
||||||
|
return pthread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsReusableThread::stop()
|
||||||
|
{
|
||||||
|
pthread->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsReusableThread::cid()
|
||||||
|
{
|
||||||
|
return pthread->cid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsReusableThread::interrupt()
|
||||||
|
{
|
||||||
|
pthread->stop_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsReusableThread::interrupted()
|
||||||
|
{
|
||||||
|
return !pthread->can_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsReusableThread::cycle()
|
||||||
|
{
|
||||||
|
return handler->cycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsReusableThread::on_thread_stop()
|
||||||
|
{
|
||||||
|
handler->on_thread_stop();
|
||||||
|
}
|
||||||
|
|
|
@ -31,34 +31,238 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
|
|
||||||
|
// the internal classes, user should never use it.
|
||||||
|
// user should use the public classes at the bellow:
|
||||||
|
// @see SrsEndlessThread, SrsOneCycleThread, SrsReusableThread
|
||||||
|
namespace internal {
|
||||||
|
/**
|
||||||
|
* the handler for the thread, callback interface.
|
||||||
|
* the thread model defines as:
|
||||||
|
* handler->on_thread_start()
|
||||||
|
* while loop:
|
||||||
|
* handler->on_before_cycle()
|
||||||
|
* handler->cycle()
|
||||||
|
* handler->on_end_cycle()
|
||||||
|
* if !loop then break for user stop thread.
|
||||||
|
* sleep(CycleIntervalMilliseconds)
|
||||||
|
* handler->on_thread_stop()
|
||||||
|
* when stop, the thread will interrupt the st_thread,
|
||||||
|
* which will cause the socket to return error and
|
||||||
|
* terminate the cycle thread.
|
||||||
|
*
|
||||||
|
* @remark why should check can_loop() in cycle method?
|
||||||
|
* when thread interrupt, the socket maybe not got EINT,
|
||||||
|
* espectially on st_usleep(), so the cycle must check the loop,
|
||||||
|
* when handler->cycle() has loop itself, for example:
|
||||||
|
* while (true):
|
||||||
|
* if (read_from_socket(skt) < 0) break;
|
||||||
|
* if thread stop when read_from_socket, it's ok, the loop will break,
|
||||||
|
* but when thread stop interrupt the s_usleep(0), then the loop is
|
||||||
|
* death loop.
|
||||||
|
* in a word, the handler->cycle() must:
|
||||||
|
* while (pthread->can_loop()):
|
||||||
|
* if (read_from_socket(skt) < 0) break;
|
||||||
|
* check the loop, then it works.
|
||||||
|
*
|
||||||
|
* @remark why should use stop_loop() to terminate thread in itself?
|
||||||
|
* in the thread itself, that is the cycle method,
|
||||||
|
* if itself want to terminate the thread, should never use stop(),
|
||||||
|
* but use stop_loop() to set the loop to false and terminate normally.
|
||||||
|
*
|
||||||
|
* @remark when should set the interval_us, and when not?
|
||||||
|
* the cycle will invoke util cannot loop, eventhough the return code of cycle is error,
|
||||||
|
* so the interval_us used to sleep for each cycle.
|
||||||
|
*/
|
||||||
|
class ISrsThreadHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsThreadHandler();
|
||||||
|
virtual ~ISrsThreadHandler();
|
||||||
|
public:
|
||||||
|
virtual void on_thread_start();
|
||||||
|
virtual int on_before_cycle();
|
||||||
|
virtual int cycle() = 0;
|
||||||
|
virtual int on_end_cycle();
|
||||||
|
virtual void on_thread_stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provides servies from st_thread_t,
|
||||||
|
* for common thread usage.
|
||||||
|
*/
|
||||||
|
class SrsThread
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
st_thread_t tid;
|
||||||
|
int _cid;
|
||||||
|
bool loop;
|
||||||
|
bool can_run;
|
||||||
|
bool really_terminated;
|
||||||
|
bool _joinable;
|
||||||
|
const char* _name;
|
||||||
|
private:
|
||||||
|
ISrsThreadHandler* handler;
|
||||||
|
int64_t cycle_interval_us;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* initialize the thread.
|
||||||
|
* @param name, human readable name for st debug.
|
||||||
|
* @param thread_handler, the cycle handler for the thread.
|
||||||
|
* @param interval_us, the sleep interval when cycle finished.
|
||||||
|
* @param joinable, if joinable, other thread must stop the thread.
|
||||||
|
* @remark if joinable, thread never quit itself, or memory leak.
|
||||||
|
* @see: https://github.com/simple-rtmp-server/srs/issues/78
|
||||||
|
* @remark about st debug, see st-1.9/README, _st_iterate_threads_flag
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* TODO: FIXME: maybe all thread must be reap by others threads,
|
||||||
|
* @see: https://github.com/simple-rtmp-server/srs/issues/77
|
||||||
|
*/
|
||||||
|
SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable);
|
||||||
|
virtual ~SrsThread();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* get the context id. @see: ISrsThreadContext.get_id().
|
||||||
|
* used for parent thread to get the id.
|
||||||
|
* @remark when start thread, parent thread will block and wait for this id ready.
|
||||||
|
*/
|
||||||
|
virtual int cid();
|
||||||
|
/**
|
||||||
|
* start the thread, invoke the cycle of handler util
|
||||||
|
* user stop the thread.
|
||||||
|
* @remark ignore any error of cycle of handler.
|
||||||
|
* @remark user can start multiple times, ignore if already started.
|
||||||
|
* @remark wait for the cid is set by thread pfn.
|
||||||
|
*/
|
||||||
|
virtual int start();
|
||||||
|
/**
|
||||||
|
* stop the thread, wait for the thread to terminate.
|
||||||
|
* @remark user can stop multiple times, ignore if already stopped.
|
||||||
|
*/
|
||||||
|
virtual void stop();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* whether the thread should loop,
|
||||||
|
* used for handler->cycle() which has a loop method,
|
||||||
|
* to check this method, break if false.
|
||||||
|
*/
|
||||||
|
virtual bool can_loop();
|
||||||
|
/**
|
||||||
|
* for the loop thread to stop the loop.
|
||||||
|
* other thread can directly use stop() to stop loop and wait for quit.
|
||||||
|
* this stop loop method only set loop to false.
|
||||||
|
*/
|
||||||
|
virtual void stop_loop();
|
||||||
|
private:
|
||||||
|
virtual void thread_cycle();
|
||||||
|
static void* thread_fun(void* arg);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the handler for the thread, callback interface.
|
* the endless thread is a loop thread never quit.
|
||||||
* the thread model defines as:
|
|
||||||
* handler->on_thread_start()
|
|
||||||
* while loop:
|
|
||||||
* handler->on_before_cycle()
|
|
||||||
* handler->cycle()
|
|
||||||
* handler->on_end_cycle()
|
|
||||||
* if !loop then break for user stop thread.
|
|
||||||
* sleep(CycleIntervalMilliseconds)
|
|
||||||
* handler->on_thread_stop()
|
|
||||||
* when stop, the thread will interrupt the st_thread,
|
|
||||||
* which will cause the socket to return error and
|
|
||||||
* terminate the cycle thread.
|
|
||||||
*
|
|
||||||
* Usage 1: loop thread never quit.
|
|
||||||
* user can create thread always running util server terminate.
|
* user can create thread always running util server terminate.
|
||||||
* the step to create a thread never stop:
|
* the step to create a thread never stop:
|
||||||
* 1. create SrsThread field, with joinable false.
|
* 1. create SrsEndlessThread field.
|
||||||
* for example:
|
* for example:
|
||||||
* class SrsStreamCache : public ISrsThreadHandler {
|
* class SrsStreamCache : public ISrsEndlessThreadHandler {
|
||||||
* public: SrsStreamCache() { pthread = new SrsThread("http-stream", this, SRS_AUTO_STREAM_SLEEP_US, false); }
|
* public: SrsStreamCache() { pthread = new SrsEndlessThread("http-stream", this); }
|
||||||
* public: virtual int cycle() {
|
* public: virtual int cycle() {
|
||||||
* // check status, start ffmpeg when stopped.
|
* // do some work never end.
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
* @remark user must use block method in cycle method, for example, sleep or socket io.
|
||||||
* Usage 2: stop by other thread.
|
*/
|
||||||
|
class ISrsEndlessThreadHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsEndlessThreadHandler();
|
||||||
|
virtual ~ISrsEndlessThreadHandler();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* the cycle method for the common thread.
|
||||||
|
* @remark user must use block method in cycle method, for example, sleep or socket io.
|
||||||
|
*/
|
||||||
|
virtual int cycle() = 0;
|
||||||
|
};
|
||||||
|
class SrsEndlessThread : public internal::ISrsThreadHandler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
internal::SrsThread* pthread;
|
||||||
|
ISrsEndlessThreadHandler* handler;
|
||||||
|
public:
|
||||||
|
SrsEndlessThread(const char* n, ISrsEndlessThreadHandler* h);
|
||||||
|
virtual ~SrsEndlessThread();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* for the endless thread, never quit.
|
||||||
|
*/
|
||||||
|
virtual int start();
|
||||||
|
// interface internal::ISrsThreadHandler
|
||||||
|
public:
|
||||||
|
virtual int cycle();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the one cycle thread is a thread do the cycle only one time,
|
||||||
|
* that is, the thread will quit when return from the cycle.
|
||||||
|
* user can create thread which stop itself,
|
||||||
|
* generally only need to provides a start method,
|
||||||
|
* the object will destroy itself then terminate the thread, @see SrsConnection
|
||||||
|
* 1. create SrsThread field
|
||||||
|
* 2. the thread quit when return from cycle.
|
||||||
|
* for example:
|
||||||
|
* class SrsConnection : public ISrsOneCycleThreadHandler {
|
||||||
|
* public: SrsConnection() { pthread = new SrsOneCycleThread("conn", this); }
|
||||||
|
* public: virtual int start() { return pthread->start(); }
|
||||||
|
* public: virtual int cycle() {
|
||||||
|
* // serve client.
|
||||||
|
* // set loop to stop to quit, stop thread itself.
|
||||||
|
* pthread->stop_loop();
|
||||||
|
* }
|
||||||
|
* public: virtual void on_thread_stop() {
|
||||||
|
* // remove the connection in thread itself.
|
||||||
|
* server->remove(this);
|
||||||
|
* }
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
class ISrsOneCycleThreadHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsOneCycleThreadHandler();
|
||||||
|
virtual ~ISrsOneCycleThreadHandler();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* the cycle method for the one cycle thread.
|
||||||
|
*/
|
||||||
|
virtual int cycle() = 0;
|
||||||
|
/**
|
||||||
|
* when thread stop, the handler can do cleanup.
|
||||||
|
* @remark this method is optional, handler can ignore it.
|
||||||
|
*/
|
||||||
|
virtual void on_thread_stop();
|
||||||
|
};
|
||||||
|
class SrsOneCycleThread : public internal::ISrsThreadHandler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
internal::SrsThread* pthread;
|
||||||
|
ISrsOneCycleThreadHandler* handler;
|
||||||
|
public:
|
||||||
|
SrsOneCycleThread(const char* n, ISrsOneCycleThreadHandler* h);
|
||||||
|
virtual ~SrsOneCycleThread();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* for the one cycle thread, quit when cycle return.
|
||||||
|
*/
|
||||||
|
virtual int start();
|
||||||
|
// interface internal::ISrsThreadHandler
|
||||||
|
public:
|
||||||
|
virtual int cycle();
|
||||||
|
virtual void on_thread_stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the reuse thread is a thread stop and start by other thread.
|
||||||
* user can create thread and stop then start again and again,
|
* user can create thread and stop then start again and again,
|
||||||
* generally must provides a start and stop method, @see SrsIngester.
|
* generally must provides a start and stop method, @see SrsIngester.
|
||||||
* the step to create a thread stop by other thread:
|
* the step to create a thread stop by other thread:
|
||||||
|
@ -73,147 +277,65 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
* // check status, start ffmpeg when stopped.
|
* // check status, start ffmpeg when stopped.
|
||||||
* }
|
* }
|
||||||
* };
|
* };
|
||||||
*
|
|
||||||
* Usage 3: stop by thread itself.
|
|
||||||
* user can create thread which stop itself,
|
|
||||||
* generally only need to provides a start method,
|
|
||||||
* the object will destroy itself then terminate the thread, @see SrsConnection
|
|
||||||
* 1. create SrsThread field, with joinable false.
|
|
||||||
* 2. owner stop thread loop, destroy itself when thread stop.
|
|
||||||
* for example:
|
|
||||||
* class SrsConnection : public ISrsThreadHandler {
|
|
||||||
* public: SrsConnection() { pthread = new SrsThread("conn", this, 0, false); }
|
|
||||||
* public: virtual int start() { return pthread->start(); }
|
|
||||||
* public: virtual int cycle() {
|
|
||||||
* // serve client.
|
|
||||||
* // set loop to stop to quit, stop thread itself.
|
|
||||||
* pthread->stop_loop();
|
|
||||||
* }
|
|
||||||
* public: virtual int on_thread_stop() {
|
|
||||||
* // remove the connection in thread itself.
|
|
||||||
* server->remove(this);
|
|
||||||
* }
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* Usage 4: loop in the cycle method.
|
|
||||||
* user can use loop code in the cycle method, @see SrsForwarder
|
|
||||||
* 1. create SrsThread field, with or without joinable is ok.
|
|
||||||
* 2. loop code in cycle method, check the can_loop() for thread to quit.
|
|
||||||
* for example:
|
|
||||||
* class SrsForwarder : public ISrsThreadHandler {
|
|
||||||
* public: virtual int cycle() {
|
|
||||||
* while (pthread->can_loop()) {
|
|
||||||
* // read msgs from queue and forward to server.
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* @remark why should check can_loop() in cycle method?
|
|
||||||
* when thread interrupt, the socket maybe not got EINT,
|
|
||||||
* espectially on st_usleep(), so the cycle must check the loop,
|
|
||||||
* when handler->cycle() has loop itself, for example:
|
|
||||||
* while (true):
|
|
||||||
* if (read_from_socket(skt) < 0) break;
|
|
||||||
* if thread stop when read_from_socket, it's ok, the loop will break,
|
|
||||||
* but when thread stop interrupt the s_usleep(0), then the loop is
|
|
||||||
* death loop.
|
|
||||||
* in a word, the handler->cycle() must:
|
|
||||||
* while (pthread->can_loop()):
|
|
||||||
* if (read_from_socket(skt) < 0) break;
|
|
||||||
* check the loop, then it works.
|
|
||||||
*
|
|
||||||
* @remark why should use stop_loop() to terminate thread in itself?
|
|
||||||
* in the thread itself, that is the cycle method,
|
|
||||||
* if itself want to terminate the thread, should never use stop(),
|
|
||||||
* but use stop_loop() to set the loop to false and terminate normally.
|
|
||||||
*
|
|
||||||
* @remark when should set the interval_us, and when not?
|
|
||||||
* the cycle will invoke util cannot loop, eventhough the return code of cycle is error,
|
|
||||||
* so the interval_us used to sleep for each cycle.
|
|
||||||
*/
|
*/
|
||||||
class ISrsThreadHandler
|
class ISrsReusableThreadHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ISrsThreadHandler();
|
ISrsReusableThreadHandler();
|
||||||
virtual ~ISrsThreadHandler();
|
virtual ~ISrsReusableThreadHandler();
|
||||||
public:
|
public:
|
||||||
virtual void on_thread_start();
|
/**
|
||||||
virtual int on_before_cycle();
|
* the cycle method for the one cycle thread.
|
||||||
|
* @remark when the cycle has its inner loop, it must check whether
|
||||||
|
* the thread is interrupted.
|
||||||
|
*/
|
||||||
virtual int cycle() = 0;
|
virtual int cycle() = 0;
|
||||||
virtual int on_end_cycle();
|
/**
|
||||||
|
* when thread stop, the handler can do cleanup.
|
||||||
|
* @remark this method is optional, handler can ignore it.
|
||||||
|
*/
|
||||||
virtual void on_thread_stop();
|
virtual void on_thread_stop();
|
||||||
};
|
};
|
||||||
|
class SrsReusableThread : public internal::ISrsThreadHandler
|
||||||
/**
|
|
||||||
* provides servies from st_thread_t,
|
|
||||||
* for common thread usage.
|
|
||||||
*/
|
|
||||||
class SrsThread
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
st_thread_t tid;
|
internal::SrsThread* pthread;
|
||||||
int _cid;
|
ISrsReusableThreadHandler* handler;
|
||||||
bool loop;
|
public:
|
||||||
bool can_run;
|
SrsReusableThread(const char* n, ISrsReusableThreadHandler* h, int64_t interval_us = 0);
|
||||||
bool really_terminated;
|
virtual ~SrsReusableThread();
|
||||||
bool _joinable;
|
|
||||||
const char* _name;
|
|
||||||
private:
|
|
||||||
ISrsThreadHandler* handler;
|
|
||||||
int64_t cycle_interval_us;
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* initialize the thread.
|
* for the reusable thread, start and stop by user.
|
||||||
* @param name, human readable name for st debug.
|
*/
|
||||||
* @param thread_handler, the cycle handler for the thread.
|
|
||||||
* @param interval_us, the sleep interval when cycle finished.
|
|
||||||
* @param joinable, if joinable, other thread must stop the thread.
|
|
||||||
* @remark if joinable, thread never quit itself, or memory leak.
|
|
||||||
* @see: https://github.com/simple-rtmp-server/srs/issues/78
|
|
||||||
* @remark about st debug, see st-1.9/README, _st_iterate_threads_flag
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* TODO: FIXME: maybe all thread must be reap by others threads,
|
|
||||||
* @see: https://github.com/simple-rtmp-server/srs/issues/77
|
|
||||||
*/
|
|
||||||
SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable);
|
|
||||||
virtual ~SrsThread();
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* get the context id. @see: ISrsThreadContext.get_id().
|
|
||||||
* used for parent thread to get the id.
|
|
||||||
* @remark when start thread, parent thread will block and wait for this id ready.
|
|
||||||
*/
|
|
||||||
virtual int cid();
|
|
||||||
/**
|
|
||||||
* start the thread, invoke the cycle of handler util
|
|
||||||
* user stop the thread.
|
|
||||||
* @remark ignore any error of cycle of handler.
|
|
||||||
* @remark user can start multiple times, ignore if already started.
|
|
||||||
* @remark wait for the cid is set by thread pfn.
|
|
||||||
*/
|
|
||||||
virtual int start();
|
virtual int start();
|
||||||
/**
|
/**
|
||||||
* stop the thread, wait for the thread to terminate.
|
* stop the thread, wait for the thread to terminate.
|
||||||
* @remark user can stop multiple times, ignore if already stopped.
|
* @remark user can stop multiple times, ignore if already stopped.
|
||||||
*/
|
*/
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* whether the thread should loop,
|
* get the context id. @see: ISrsThreadContext.get_id().
|
||||||
* used for handler->cycle() which has a loop method,
|
* used for parent thread to get the id.
|
||||||
* to check this method, break if false.
|
* @remark when start thread, parent thread will block and wait for this id ready.
|
||||||
*/
|
*/
|
||||||
virtual bool can_loop();
|
virtual int cid();
|
||||||
/**
|
/**
|
||||||
* for the loop thread to stop the loop.
|
* interrupt the thread to stop loop.
|
||||||
* other thread can directly use stop() to stop loop and wait for quit.
|
* we only set the loop flag to false, not really interrupt the thread.
|
||||||
* this stop loop method only set loop to false.
|
*/
|
||||||
*/
|
virtual void interrupt();
|
||||||
virtual void stop_loop();
|
/**
|
||||||
private:
|
* whether the thread is interrupted,
|
||||||
virtual void thread_cycle();
|
* for the cycle has its loop, the inner loop should quit when thread
|
||||||
static void* thread_fun(void* arg);
|
* is interrupted.
|
||||||
|
*/
|
||||||
|
virtual bool interrupted();
|
||||||
|
// interface internal::ISrsThreadHandler
|
||||||
|
public:
|
||||||
|
virtual int cycle();
|
||||||
|
virtual void on_thread_stop();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue