正在显示
4 个修改的文件
包含
355 行增加
和
353 行删除
| @@ -26,6 +26,230 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -26,6 +26,230 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 26 | #include <srs_kernel_error.hpp> | 26 | #include <srs_kernel_error.hpp> |
| 27 | #include <srs_kernel_log.hpp> | 27 | #include <srs_kernel_log.hpp> |
| 28 | 28 | ||
| 29 | +namespace internal | ||
| 30 | +{ | ||
| 31 | + ISrsThreadHandler::ISrsThreadHandler() | ||
| 32 | + { | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + ISrsThreadHandler::~ISrsThreadHandler() | ||
| 36 | + { | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + void ISrsThreadHandler::on_thread_start() | ||
| 40 | + { | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + int ISrsThreadHandler::on_before_cycle() | ||
| 44 | + { | ||
| 45 | + int ret = ERROR_SUCCESS; | ||
| 46 | + return ret; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + int ISrsThreadHandler::on_end_cycle() | ||
| 50 | + { | ||
| 51 | + int ret = ERROR_SUCCESS; | ||
| 52 | + return ret; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + void ISrsThreadHandler::on_thread_stop() | ||
| 56 | + { | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + SrsThread::SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable) | ||
| 60 | + { | ||
| 61 | + _name = name; | ||
| 62 | + handler = thread_handler; | ||
| 63 | + cycle_interval_us = interval_us; | ||
| 64 | + | ||
| 65 | + tid = NULL; | ||
| 66 | + loop = false; | ||
| 67 | + really_terminated = true; | ||
| 68 | + _cid = -1; | ||
| 69 | + _joinable = joinable; | ||
| 70 | + disposed = false; | ||
| 71 | + | ||
| 72 | + // in start(), the thread cycle method maybe stop and remove the thread itself, | ||
| 73 | + // and the thread start() is waiting for the _cid, and segment fault then. | ||
| 74 | + // @see https://github.com/simple-rtmp-server/srs/issues/110 | ||
| 75 | + // thread will set _cid, callback on_thread_start(), then wait for the can_run signal. | ||
| 76 | + can_run = false; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + SrsThread::~SrsThread() | ||
| 80 | + { | ||
| 81 | + stop(); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + int SrsThread::cid() | ||
| 85 | + { | ||
| 86 | + return _cid; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + int SrsThread::start() | ||
| 90 | + { | ||
| 91 | + int ret = ERROR_SUCCESS; | ||
| 92 | + | ||
| 93 | + if(tid) { | ||
| 94 | + srs_info("thread %s already running.", _name); | ||
| 95 | + return ret; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){ | ||
| 99 | + ret = ERROR_ST_CREATE_CYCLE_THREAD; | ||
| 100 | + srs_error("st_thread_create failed. ret=%d", ret); | ||
| 101 | + return ret; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + // we set to loop to true for thread to run. | ||
| 105 | + loop = true; | ||
| 106 | + | ||
| 107 | + // wait for cid to ready, for parent thread to get the cid. | ||
| 108 | + while (_cid < 0 && loop) { | ||
| 109 | + st_usleep(10 * 1000); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + // now, cycle thread can run. | ||
| 113 | + can_run = true; | ||
| 114 | + | ||
| 115 | + return ret; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + void SrsThread::stop() | ||
| 119 | + { | ||
| 120 | + if (!tid) { | ||
| 121 | + return; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + loop = false; | ||
| 125 | + | ||
| 126 | + dispose(); | ||
| 127 | + | ||
| 128 | + tid = NULL; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + bool SrsThread::can_loop() | ||
| 132 | + { | ||
| 133 | + return loop; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + void SrsThread::stop_loop() | ||
| 137 | + { | ||
| 138 | + loop = false; | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + void SrsThread::dispose() | ||
| 142 | + { | ||
| 143 | + if (disposed) { | ||
| 144 | + return; | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + // the interrupt will cause the socket to read/write error, | ||
| 148 | + // which will terminate the cycle thread. | ||
| 149 | + st_thread_interrupt(tid); | ||
| 150 | + | ||
| 151 | + // when joinable, wait util quit. | ||
| 152 | + if (_joinable) { | ||
| 153 | + // wait the thread to exit. | ||
| 154 | + int ret = st_thread_join(tid, NULL); | ||
| 155 | + if (ret) { | ||
| 156 | + srs_warn("core: ignore join thread failed."); | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + // wait the thread actually terminated. | ||
| 161 | + // sometimes the thread join return -1, for example, | ||
| 162 | + // when thread use st_recvfrom, the thread join return -1. | ||
| 163 | + // so here, we use a variable to ensure the thread stopped. | ||
| 164 | + // @remark even the thread not joinable, we must ensure the thread stopped when stop. | ||
| 165 | + while (!really_terminated) { | ||
| 166 | + st_usleep(10 * 1000); | ||
| 167 | + | ||
| 168 | + if (really_terminated) { | ||
| 169 | + break; | ||
| 170 | + } | ||
| 171 | + srs_warn("core: wait thread to actually terminated"); | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + disposed = true; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + void SrsThread::thread_cycle() | ||
| 178 | + { | ||
| 179 | + int ret = ERROR_SUCCESS; | ||
| 180 | + | ||
| 181 | + _srs_context->generate_id(); | ||
| 182 | + srs_info("thread %s cycle start", _name); | ||
| 183 | + | ||
| 184 | + _cid = _srs_context->get_id(); | ||
| 185 | + | ||
| 186 | + srs_assert(handler); | ||
| 187 | + handler->on_thread_start(); | ||
| 188 | + | ||
| 189 | + // thread is running now. | ||
| 190 | + really_terminated = false; | ||
| 191 | + | ||
| 192 | + // wait for cid to ready, for parent thread to get the cid. | ||
| 193 | + while (!can_run && loop) { | ||
| 194 | + st_usleep(10 * 1000); | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + while (loop) { | ||
| 198 | + if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) { | ||
| 199 | + srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret); | ||
| 200 | + goto failed; | ||
| 201 | + } | ||
| 202 | + srs_info("thread %s on before cycle success"); | ||
| 203 | + | ||
| 204 | + if ((ret = handler->cycle()) != ERROR_SUCCESS) { | ||
| 205 | + if (!srs_is_client_gracefully_close(ret) && !srs_is_system_control_error(ret)) { | ||
| 206 | + srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret); | ||
| 207 | + } | ||
| 208 | + goto failed; | ||
| 209 | + } | ||
| 210 | + srs_info("thread %s cycle success", _name); | ||
| 211 | + | ||
| 212 | + if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) { | ||
| 213 | + srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret); | ||
| 214 | + goto failed; | ||
| 215 | + } | ||
| 216 | + srs_info("thread %s on end cycle success", _name); | ||
| 217 | + | ||
| 218 | + failed: | ||
| 219 | + if (!loop) { | ||
| 220 | + break; | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + // to improve performance, donot sleep when interval is zero. | ||
| 224 | + // @see: https://github.com/simple-rtmp-server/srs/issues/237 | ||
| 225 | + if (cycle_interval_us != 0) { | ||
| 226 | + st_usleep(cycle_interval_us); | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | + | ||
| 230 | + // readly terminated now. | ||
| 231 | + really_terminated = true; | ||
| 232 | + | ||
| 233 | + handler->on_thread_stop(); | ||
| 234 | + srs_info("thread %s cycle finished", _name); | ||
| 235 | + | ||
| 236 | + // when thread terminated normally, also disposed. | ||
| 237 | + disposed = true; | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + void* SrsThread::thread_fun(void* arg) | ||
| 241 | + { | ||
| 242 | + SrsThread* obj = (SrsThread*)arg; | ||
| 243 | + srs_assert(obj); | ||
| 244 | + | ||
| 245 | + obj->thread_cycle(); | ||
| 246 | + | ||
| 247 | + st_thread_exit(NULL); | ||
| 248 | + | ||
| 249 | + return NULL; | ||
| 250 | + } | ||
| 251 | +} | ||
| 252 | + | ||
| 29 | SrsStSocket::SrsStSocket(st_netfd_t client_stfd) | 253 | SrsStSocket::SrsStSocket(st_netfd_t client_stfd) |
| 30 | { | 254 | { |
| 31 | stfd = client_stfd; | 255 | stfd = client_stfd; |
| @@ -35,6 +35,137 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -35,6 +35,137 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 35 | #include <srs_app_st.hpp> | 35 | #include <srs_app_st.hpp> |
| 36 | #include <srs_rtmp_io.hpp> | 36 | #include <srs_rtmp_io.hpp> |
| 37 | 37 | ||
| 38 | +// the internal classes, user should never use it. | ||
| 39 | +// user should use the public classes at the bellow: | ||
| 40 | +// @see SrsEndlessThread, SrsOneCycleThread, SrsReusableThread | ||
| 41 | +namespace internal | ||
| 42 | +{ | ||
| 43 | + /** | ||
| 44 | + * the handler for the thread, callback interface. | ||
| 45 | + * the thread model defines as: | ||
| 46 | + * handler->on_thread_start() | ||
| 47 | + * while loop: | ||
| 48 | + * handler->on_before_cycle() | ||
| 49 | + * handler->cycle() | ||
| 50 | + * handler->on_end_cycle() | ||
| 51 | + * if !loop then break for user stop thread. | ||
| 52 | + * sleep(CycleIntervalMilliseconds) | ||
| 53 | + * handler->on_thread_stop() | ||
| 54 | + * when stop, the thread will interrupt the st_thread, | ||
| 55 | + * which will cause the socket to return error and | ||
| 56 | + * terminate the cycle thread. | ||
| 57 | + * | ||
| 58 | + * @remark why should check can_loop() in cycle method? | ||
| 59 | + * when thread interrupt, the socket maybe not got EINT, | ||
| 60 | + * espectially on st_usleep(), so the cycle must check the loop, | ||
| 61 | + * when handler->cycle() has loop itself, for example: | ||
| 62 | + * while (true): | ||
| 63 | + * if (read_from_socket(skt) < 0) break; | ||
| 64 | + * if thread stop when read_from_socket, it's ok, the loop will break, | ||
| 65 | + * but when thread stop interrupt the s_usleep(0), then the loop is | ||
| 66 | + * death loop. | ||
| 67 | + * in a word, the handler->cycle() must: | ||
| 68 | + * while (pthread->can_loop()): | ||
| 69 | + * if (read_from_socket(skt) < 0) break; | ||
| 70 | + * check the loop, then it works. | ||
| 71 | + * | ||
| 72 | + * @remark why should use stop_loop() to terminate thread in itself? | ||
| 73 | + * in the thread itself, that is the cycle method, | ||
| 74 | + * if itself want to terminate the thread, should never use stop(), | ||
| 75 | + * but use stop_loop() to set the loop to false and terminate normally. | ||
| 76 | + * | ||
| 77 | + * @remark when should set the interval_us, and when not? | ||
| 78 | + * the cycle will invoke util cannot loop, eventhough the return code of cycle is error, | ||
| 79 | + * so the interval_us used to sleep for each cycle. | ||
| 80 | + */ | ||
| 81 | + class ISrsThreadHandler | ||
| 82 | + { | ||
| 83 | + public: | ||
| 84 | + ISrsThreadHandler(); | ||
| 85 | + virtual ~ISrsThreadHandler(); | ||
| 86 | + public: | ||
| 87 | + virtual void on_thread_start(); | ||
| 88 | + virtual int on_before_cycle(); | ||
| 89 | + virtual int cycle() = 0; | ||
| 90 | + virtual int on_end_cycle(); | ||
| 91 | + virtual void on_thread_stop(); | ||
| 92 | + }; | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * provides servies from st_thread_t, | ||
| 96 | + * for common thread usage. | ||
| 97 | + */ | ||
| 98 | + class SrsThread | ||
| 99 | + { | ||
| 100 | + private: | ||
| 101 | + st_thread_t tid; | ||
| 102 | + int _cid; | ||
| 103 | + bool loop; | ||
| 104 | + bool can_run; | ||
| 105 | + bool really_terminated; | ||
| 106 | + bool _joinable; | ||
| 107 | + const char* _name; | ||
| 108 | + bool disposed; | ||
| 109 | + private: | ||
| 110 | + ISrsThreadHandler* handler; | ||
| 111 | + int64_t cycle_interval_us; | ||
| 112 | + public: | ||
| 113 | + /** | ||
| 114 | + * initialize the thread. | ||
| 115 | + * @param name, human readable name for st debug. | ||
| 116 | + * @param thread_handler, the cycle handler for the thread. | ||
| 117 | + * @param interval_us, the sleep interval when cycle finished. | ||
| 118 | + * @param joinable, if joinable, other thread must stop the thread. | ||
| 119 | + * @remark if joinable, thread never quit itself, or memory leak. | ||
| 120 | + * @see: https://github.com/simple-rtmp-server/srs/issues/78 | ||
| 121 | + * @remark about st debug, see st-1.9/README, _st_iterate_threads_flag | ||
| 122 | + */ | ||
| 123 | + /** | ||
| 124 | + * TODO: FIXME: maybe all thread must be reap by others threads, | ||
| 125 | + * @see: https://github.com/simple-rtmp-server/srs/issues/77 | ||
| 126 | + */ | ||
| 127 | + SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable); | ||
| 128 | + virtual ~SrsThread(); | ||
| 129 | + public: | ||
| 130 | + /** | ||
| 131 | + * get the context id. @see: ISrsThreadContext.get_id(). | ||
| 132 | + * used for parent thread to get the id. | ||
| 133 | + * @remark when start thread, parent thread will block and wait for this id ready. | ||
| 134 | + */ | ||
| 135 | + virtual int cid(); | ||
| 136 | + /** | ||
| 137 | + * start the thread, invoke the cycle of handler util | ||
| 138 | + * user stop the thread. | ||
| 139 | + * @remark ignore any error of cycle of handler. | ||
| 140 | + * @remark user can start multiple times, ignore if already started. | ||
| 141 | + * @remark wait for the cid is set by thread pfn. | ||
| 142 | + */ | ||
| 143 | + virtual int start(); | ||
| 144 | + /** | ||
| 145 | + * stop the thread, wait for the thread to terminate. | ||
| 146 | + * @remark user can stop multiple times, ignore if already stopped. | ||
| 147 | + */ | ||
| 148 | + virtual void stop(); | ||
| 149 | + public: | ||
| 150 | + /** | ||
| 151 | + * whether the thread should loop, | ||
| 152 | + * used for handler->cycle() which has a loop method, | ||
| 153 | + * to check this method, break if false. | ||
| 154 | + */ | ||
| 155 | + virtual bool can_loop(); | ||
| 156 | + /** | ||
| 157 | + * for the loop thread to stop the loop. | ||
| 158 | + * other thread can directly use stop() to stop loop and wait for quit. | ||
| 159 | + * this stop loop method only set loop to false. | ||
| 160 | + */ | ||
| 161 | + virtual void stop_loop(); | ||
| 162 | + private: | ||
| 163 | + virtual void dispose(); | ||
| 164 | + virtual void thread_cycle(); | ||
| 165 | + static void* thread_fun(void* arg); | ||
| 166 | + }; | ||
| 167 | +} | ||
| 168 | + | ||
| 38 | /** | 169 | /** |
| 39 | * the socket provides TCP socket over st, | 170 | * the socket provides TCP socket over st, |
| 40 | * that is, the sync socket mechanism. | 171 | * that is, the sync socket mechanism. |
| @@ -26,229 +26,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -26,229 +26,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 26 | #include <srs_kernel_error.hpp> | 26 | #include <srs_kernel_error.hpp> |
| 27 | #include <srs_kernel_log.hpp> | 27 | #include <srs_kernel_log.hpp> |
| 28 | 28 | ||
| 29 | -namespace internal { | ||
| 30 | - ISrsThreadHandler::ISrsThreadHandler() | ||
| 31 | - { | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | - ISrsThreadHandler::~ISrsThreadHandler() | ||
| 35 | - { | ||
| 36 | - } | ||
| 37 | - | ||
| 38 | - void ISrsThreadHandler::on_thread_start() | ||
| 39 | - { | ||
| 40 | - } | ||
| 41 | - | ||
| 42 | - int ISrsThreadHandler::on_before_cycle() | ||
| 43 | - { | ||
| 44 | - int ret = ERROR_SUCCESS; | ||
| 45 | - return ret; | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - int ISrsThreadHandler::on_end_cycle() | ||
| 49 | - { | ||
| 50 | - int ret = ERROR_SUCCESS; | ||
| 51 | - return ret; | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - void ISrsThreadHandler::on_thread_stop() | ||
| 55 | - { | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | - SrsThread::SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable) | ||
| 59 | - { | ||
| 60 | - _name = name; | ||
| 61 | - handler = thread_handler; | ||
| 62 | - cycle_interval_us = interval_us; | ||
| 63 | - | ||
| 64 | - tid = NULL; | ||
| 65 | - loop = false; | ||
| 66 | - really_terminated = true; | ||
| 67 | - _cid = -1; | ||
| 68 | - _joinable = joinable; | ||
| 69 | - disposed = false; | ||
| 70 | - | ||
| 71 | - // in start(), the thread cycle method maybe stop and remove the thread itself, | ||
| 72 | - // and the thread start() is waiting for the _cid, and segment fault then. | ||
| 73 | - // @see https://github.com/simple-rtmp-server/srs/issues/110 | ||
| 74 | - // thread will set _cid, callback on_thread_start(), then wait for the can_run signal. | ||
| 75 | - can_run = false; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - SrsThread::~SrsThread() | ||
| 79 | - { | ||
| 80 | - stop(); | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - int SrsThread::cid() | ||
| 84 | - { | ||
| 85 | - return _cid; | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - int SrsThread::start() | ||
| 89 | - { | ||
| 90 | - int ret = ERROR_SUCCESS; | ||
| 91 | - | ||
| 92 | - if(tid) { | ||
| 93 | - srs_info("thread %s already running.", _name); | ||
| 94 | - return ret; | ||
| 95 | - } | ||
| 96 | - | ||
| 97 | - if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){ | ||
| 98 | - ret = ERROR_ST_CREATE_CYCLE_THREAD; | ||
| 99 | - srs_error("st_thread_create failed. ret=%d", ret); | ||
| 100 | - return ret; | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - // we set to loop to true for thread to run. | ||
| 104 | - loop = true; | ||
| 105 | - | ||
| 106 | - // wait for cid to ready, for parent thread to get the cid. | ||
| 107 | - while (_cid < 0 && loop) { | ||
| 108 | - st_usleep(10 * 1000); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | - // now, cycle thread can run. | ||
| 112 | - can_run = true; | ||
| 113 | - | ||
| 114 | - return ret; | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - void SrsThread::stop() | ||
| 118 | - { | ||
| 119 | - if (!tid) { | ||
| 120 | - return; | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | - loop = false; | ||
| 124 | - | ||
| 125 | - dispose(); | ||
| 126 | - | ||
| 127 | - tid = NULL; | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - bool SrsThread::can_loop() | ||
| 131 | - { | ||
| 132 | - return loop; | ||
| 133 | - } | ||
| 134 | - | ||
| 135 | - void SrsThread::stop_loop() | ||
| 136 | - { | ||
| 137 | - loop = false; | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - void SrsThread::dispose() | ||
| 141 | - { | ||
| 142 | - if (disposed) { | ||
| 143 | - return; | ||
| 144 | - } | ||
| 145 | - | ||
| 146 | - // the interrupt will cause the socket to read/write error, | ||
| 147 | - // which will terminate the cycle thread. | ||
| 148 | - st_thread_interrupt(tid); | ||
| 149 | - | ||
| 150 | - // when joinable, wait util quit. | ||
| 151 | - if (_joinable) { | ||
| 152 | - // wait the thread to exit. | ||
| 153 | - int ret = st_thread_join(tid, NULL); | ||
| 154 | - if (ret) { | ||
| 155 | - srs_warn("core: ignore join thread failed."); | ||
| 156 | - } | ||
| 157 | - } | ||
| 158 | - | ||
| 159 | - // wait the thread actually terminated. | ||
| 160 | - // sometimes the thread join return -1, for example, | ||
| 161 | - // when thread use st_recvfrom, the thread join return -1. | ||
| 162 | - // so here, we use a variable to ensure the thread stopped. | ||
| 163 | - // @remark even the thread not joinable, we must ensure the thread stopped when stop. | ||
| 164 | - while (!really_terminated) { | ||
| 165 | - st_usleep(10 * 1000); | ||
| 166 | - | ||
| 167 | - if (really_terminated) { | ||
| 168 | - break; | ||
| 169 | - } | ||
| 170 | - srs_warn("core: wait thread to actually terminated"); | ||
| 171 | - } | ||
| 172 | - | ||
| 173 | - disposed = true; | ||
| 174 | - } | ||
| 175 | - | ||
| 176 | - void SrsThread::thread_cycle() | ||
| 177 | - { | ||
| 178 | - int ret = ERROR_SUCCESS; | ||
| 179 | - | ||
| 180 | - _srs_context->generate_id(); | ||
| 181 | - srs_info("thread %s cycle start", _name); | ||
| 182 | - | ||
| 183 | - _cid = _srs_context->get_id(); | ||
| 184 | - | ||
| 185 | - srs_assert(handler); | ||
| 186 | - handler->on_thread_start(); | ||
| 187 | - | ||
| 188 | - // thread is running now. | ||
| 189 | - really_terminated = false; | ||
| 190 | - | ||
| 191 | - // wait for cid to ready, for parent thread to get the cid. | ||
| 192 | - while (!can_run && loop) { | ||
| 193 | - st_usleep(10 * 1000); | ||
| 194 | - } | ||
| 195 | - | ||
| 196 | - while (loop) { | ||
| 197 | - if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) { | ||
| 198 | - srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret); | ||
| 199 | - goto failed; | ||
| 200 | - } | ||
| 201 | - srs_info("thread %s on before cycle success"); | ||
| 202 | - | ||
| 203 | - if ((ret = handler->cycle()) != ERROR_SUCCESS) { | ||
| 204 | - if (!srs_is_client_gracefully_close(ret) && !srs_is_system_control_error(ret)) { | ||
| 205 | - srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret); | ||
| 206 | - } | ||
| 207 | - goto failed; | ||
| 208 | - } | ||
| 209 | - srs_info("thread %s cycle success", _name); | ||
| 210 | - | ||
| 211 | - if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) { | ||
| 212 | - srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret); | ||
| 213 | - goto failed; | ||
| 214 | - } | ||
| 215 | - srs_info("thread %s on end cycle success", _name); | ||
| 216 | - | ||
| 217 | - failed: | ||
| 218 | - if (!loop) { | ||
| 219 | - break; | ||
| 220 | - } | ||
| 221 | - | ||
| 222 | - // to improve performance, donot sleep when interval is zero. | ||
| 223 | - // @see: https://github.com/simple-rtmp-server/srs/issues/237 | ||
| 224 | - if (cycle_interval_us != 0) { | ||
| 225 | - st_usleep(cycle_interval_us); | ||
| 226 | - } | ||
| 227 | - } | ||
| 228 | - | ||
| 229 | - // readly terminated now. | ||
| 230 | - really_terminated = true; | ||
| 231 | - | ||
| 232 | - handler->on_thread_stop(); | ||
| 233 | - srs_info("thread %s cycle finished", _name); | ||
| 234 | - | ||
| 235 | - // when thread terminated normally, also disposed. | ||
| 236 | - disposed = true; | ||
| 237 | - } | ||
| 238 | - | ||
| 239 | - void* SrsThread::thread_fun(void* arg) | ||
| 240 | - { | ||
| 241 | - SrsThread* obj = (SrsThread*)arg; | ||
| 242 | - srs_assert(obj); | ||
| 243 | - | ||
| 244 | - obj->thread_cycle(); | ||
| 245 | - | ||
| 246 | - st_thread_exit(NULL); | ||
| 247 | - | ||
| 248 | - return NULL; | ||
| 249 | - } | ||
| 250 | -} | ||
| 251 | - | ||
| 252 | ISrsEndlessThreadHandler::ISrsEndlessThreadHandler() | 29 | ISrsEndlessThreadHandler::ISrsEndlessThreadHandler() |
| 253 | { | 30 | { |
| 254 | } | 31 | } |
| @@ -31,136 +31,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -31,136 +31,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 31 | 31 | ||
| 32 | #include <srs_app_st.hpp> | 32 | #include <srs_app_st.hpp> |
| 33 | 33 | ||
| 34 | -// the internal classes, user should never use it. | ||
| 35 | -// user should use the public classes at the bellow: | ||
| 36 | -// @see SrsEndlessThread, SrsOneCycleThread, SrsReusableThread | ||
| 37 | -namespace internal { | ||
| 38 | - /** | ||
| 39 | - * the handler for the thread, callback interface. | ||
| 40 | - * the thread model defines as: | ||
| 41 | - * handler->on_thread_start() | ||
| 42 | - * while loop: | ||
| 43 | - * handler->on_before_cycle() | ||
| 44 | - * handler->cycle() | ||
| 45 | - * handler->on_end_cycle() | ||
| 46 | - * if !loop then break for user stop thread. | ||
| 47 | - * sleep(CycleIntervalMilliseconds) | ||
| 48 | - * handler->on_thread_stop() | ||
| 49 | - * when stop, the thread will interrupt the st_thread, | ||
| 50 | - * which will cause the socket to return error and | ||
| 51 | - * terminate the cycle thread. | ||
| 52 | - * | ||
| 53 | - * @remark why should check can_loop() in cycle method? | ||
| 54 | - * when thread interrupt, the socket maybe not got EINT, | ||
| 55 | - * espectially on st_usleep(), so the cycle must check the loop, | ||
| 56 | - * when handler->cycle() has loop itself, for example: | ||
| 57 | - * while (true): | ||
| 58 | - * if (read_from_socket(skt) < 0) break; | ||
| 59 | - * if thread stop when read_from_socket, it's ok, the loop will break, | ||
| 60 | - * but when thread stop interrupt the s_usleep(0), then the loop is | ||
| 61 | - * death loop. | ||
| 62 | - * in a word, the handler->cycle() must: | ||
| 63 | - * while (pthread->can_loop()): | ||
| 64 | - * if (read_from_socket(skt) < 0) break; | ||
| 65 | - * check the loop, then it works. | ||
| 66 | - * | ||
| 67 | - * @remark why should use stop_loop() to terminate thread in itself? | ||
| 68 | - * in the thread itself, that is the cycle method, | ||
| 69 | - * if itself want to terminate the thread, should never use stop(), | ||
| 70 | - * but use stop_loop() to set the loop to false and terminate normally. | ||
| 71 | - * | ||
| 72 | - * @remark when should set the interval_us, and when not? | ||
| 73 | - * the cycle will invoke util cannot loop, eventhough the return code of cycle is error, | ||
| 74 | - * so the interval_us used to sleep for each cycle. | ||
| 75 | - */ | ||
| 76 | - class ISrsThreadHandler | ||
| 77 | - { | ||
| 78 | - public: | ||
| 79 | - ISrsThreadHandler(); | ||
| 80 | - virtual ~ISrsThreadHandler(); | ||
| 81 | - public: | ||
| 82 | - virtual void on_thread_start(); | ||
| 83 | - virtual int on_before_cycle(); | ||
| 84 | - virtual int cycle() = 0; | ||
| 85 | - virtual int on_end_cycle(); | ||
| 86 | - virtual void on_thread_stop(); | ||
| 87 | - }; | ||
| 88 | - | ||
| 89 | - /** | ||
| 90 | - * provides servies from st_thread_t, | ||
| 91 | - * for common thread usage. | ||
| 92 | - */ | ||
| 93 | - class SrsThread | ||
| 94 | - { | ||
| 95 | - private: | ||
| 96 | - st_thread_t tid; | ||
| 97 | - int _cid; | ||
| 98 | - bool loop; | ||
| 99 | - bool can_run; | ||
| 100 | - bool really_terminated; | ||
| 101 | - bool _joinable; | ||
| 102 | - const char* _name; | ||
| 103 | - bool disposed; | ||
| 104 | - private: | ||
| 105 | - ISrsThreadHandler* handler; | ||
| 106 | - int64_t cycle_interval_us; | ||
| 107 | - public: | ||
| 108 | - /** | ||
| 109 | - * initialize the thread. | ||
| 110 | - * @param name, human readable name for st debug. | ||
| 111 | - * @param thread_handler, the cycle handler for the thread. | ||
| 112 | - * @param interval_us, the sleep interval when cycle finished. | ||
| 113 | - * @param joinable, if joinable, other thread must stop the thread. | ||
| 114 | - * @remark if joinable, thread never quit itself, or memory leak. | ||
| 115 | - * @see: https://github.com/simple-rtmp-server/srs/issues/78 | ||
| 116 | - * @remark about st debug, see st-1.9/README, _st_iterate_threads_flag | ||
| 117 | - */ | ||
| 118 | - /** | ||
| 119 | - * TODO: FIXME: maybe all thread must be reap by others threads, | ||
| 120 | - * @see: https://github.com/simple-rtmp-server/srs/issues/77 | ||
| 121 | - */ | ||
| 122 | - SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable); | ||
| 123 | - virtual ~SrsThread(); | ||
| 124 | - public: | ||
| 125 | - /** | ||
| 126 | - * get the context id. @see: ISrsThreadContext.get_id(). | ||
| 127 | - * used for parent thread to get the id. | ||
| 128 | - * @remark when start thread, parent thread will block and wait for this id ready. | ||
| 129 | - */ | ||
| 130 | - virtual int cid(); | ||
| 131 | - /** | ||
| 132 | - * start the thread, invoke the cycle of handler util | ||
| 133 | - * user stop the thread. | ||
| 134 | - * @remark ignore any error of cycle of handler. | ||
| 135 | - * @remark user can start multiple times, ignore if already started. | ||
| 136 | - * @remark wait for the cid is set by thread pfn. | ||
| 137 | - */ | ||
| 138 | - virtual int start(); | ||
| 139 | - /** | ||
| 140 | - * stop the thread, wait for the thread to terminate. | ||
| 141 | - * @remark user can stop multiple times, ignore if already stopped. | ||
| 142 | - */ | ||
| 143 | - virtual void stop(); | ||
| 144 | - public: | ||
| 145 | - /** | ||
| 146 | - * whether the thread should loop, | ||
| 147 | - * used for handler->cycle() which has a loop method, | ||
| 148 | - * to check this method, break if false. | ||
| 149 | - */ | ||
| 150 | - virtual bool can_loop(); | ||
| 151 | - /** | ||
| 152 | - * for the loop thread to stop the loop. | ||
| 153 | - * other thread can directly use stop() to stop loop and wait for quit. | ||
| 154 | - * this stop loop method only set loop to false. | ||
| 155 | - */ | ||
| 156 | - virtual void stop_loop(); | ||
| 157 | - private: | ||
| 158 | - virtual void dispose(); | ||
| 159 | - virtual void thread_cycle(); | ||
| 160 | - static void* thread_fun(void* arg); | ||
| 161 | - }; | ||
| 162 | -} | ||
| 163 | - | ||
| 164 | /** | 34 | /** |
| 165 | * the endless thread is a loop thread never quit. | 35 | * the endless thread is a loop thread never quit. |
| 166 | * user can create thread always running util server terminate. | 36 | * user can create thread always running util server terminate. |
-
请 注册 或 登录 后发表评论