From cc6cdb96fbb195f495e6e25eec8c6afa0674570c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 22 Sep 2023 16:06:04 +0800 Subject: [PATCH] Networking: support timeout on Linux --- src/common/networking_linux.c | 7 +++--- src/common/thread.h | 40 +++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/common/networking_linux.c b/src/common/networking_linux.c index 7fb6fade5..37c796276 100644 --- a/src/common/networking_linux.c +++ b/src/common/networking_linux.c @@ -77,7 +77,8 @@ bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, con bool ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer, uint32_t timeout) { #ifdef FF_HAVE_THREADS - ffThreadJoin(state->thread); + if (!ffThreadJoin(state->thread, timeout)) + return false; #endif if(state->sockfd == -1) return false; @@ -85,8 +86,8 @@ bool ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer, ui if(timeout > 0) { struct timeval timev; - timev.tv_sec = 0; - timev.tv_usec = (__typeof__(timev.tv_usec)) (timeout * 1000); //milliseconds to microseconds + timev.tv_sec = timeout / 1000; + timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); //milliseconds to microseconds setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev)); } diff --git a/src/common/thread.h b/src/common/thread.h index 0b8989c4e..55b4c5be7 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -10,6 +10,7 @@ #include #include #include + #include #define FF_THREAD_MUTEX_INITIALIZER SRWLOCK_INIT typedef SRWLOCK FFThreadMutex; typedef HANDLE FFThreadType; @@ -21,9 +22,23 @@ #define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) static __stdcall unsigned fn ## ThreadMain (void* data) { fn((paramType)data); return 0; } #define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) static __stdcall unsigned fn ## ThreadMain () { fn(); return 0; } static inline void ffThreadDetach(FFThreadType thread) { CloseHandle(thread); } - static inline void ffThreadJoin(FFThreadType thread) { WaitForSingleObject(thread, 0xffffffff /*INFINITE*/); } + static inline bool ffThreadJoin(FFThreadType thread, uint32_t timeout) + { + if (WaitForSingleObject(thread, timeout == 0 ? (DWORD) -1 : timeout) != 0 /*WAIT_OBJECT_0*/) + { + TerminateThread(thread, (DWORD) -1); + CloseHandle(thread); + return false; + } + CloseHandle(thread); + return true; + } #else #include + #include + #if __has_include() + #include + #endif #define FF_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER typedef pthread_mutex_t FFThreadMutex; typedef pthread_t FFThreadType; @@ -37,7 +52,28 @@ #define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) static void* fn ## ThreadMain (void* data) { fn((paramType)data); return NULL; } #define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) static void* fn ## ThreadMain () { fn(); return NULL; } static inline void ffThreadDetach(FFThreadType thread) { pthread_detach(thread); } - static inline void ffThreadJoin(FFThreadType thread) { pthread_join(thread, NULL); } + static inline bool ffThreadJoin(FFThreadType thread, FF_MAYBE_UNUSED uint32_t timeout) + { + #if (defined(__linux__) && !defined(__ANDROID__)) || __has_include() + if (timeout > 0) + { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) + { + ts.tv_sec += ts.tv_sec / 1000; + ts.tv_nsec += (ts.tv_nsec % 1000) * 1000000; + if (pthread_timedjoin_np(thread, NULL, &ts) != 0) + { + pthread_kill(thread, SIGTERM); + return false; + } + return true; + } + } + #endif + pthread_join(thread, NULL); + return true; + } #endif #else //FF_HAVE_THREADS #define FF_THREAD_MUTEX_INITIALIZER 0