@@ -71,6 +71,13 @@ net_messages_t *normalqueue;
7171HANDLE hNetThread;
7272DWORD dwNetThreadId;
7373CRITICAL_SECTION net_cs;
74+ #else
75+ pthread_mutex_t net_mutex;
76+ pthread_t hNetThread;
77+ #endif
78+
79+ #ifdef REHLDS_FIXES
80+ volatile bool net_thread_terminated;
7481#endif
7582
7683cvar_t net_address = { " net_address" , " " , 0 , 0 .0f , NULL };
@@ -100,22 +107,26 @@ cvar_t net_graphpos = { "net_graphpos", "1", FCVAR_ARCHIVE, 0.0f, NULL };
100107
101108void NET_ThreadLock ()
102109{
103- #ifdef _WIN32
104110 if (use_thread && net_thread_initialized)
105111 {
112+ #ifdef _WIN32
106113 EnterCriticalSection (&net_cs);
107- }
114+ #else
115+ pthread_mutex_lock (&net_mutex);
108116#endif // _WIN32
117+ }
109118}
110119
111120void NET_ThreadUnlock ()
112121{
113- #ifdef _WIN32
114122 if (use_thread && net_thread_initialized)
115123 {
124+ #ifdef _WIN32
116125 LeaveCriticalSection (&net_cs);
117- }
126+ #else
127+ pthread_mutex_unlock (&net_mutex);
118128#endif // _WIN32
129+ }
119130}
120131
121132unsigned short Q_ntohs (unsigned short netshort)
@@ -1112,14 +1123,20 @@ int NET_Sleep()
11121123 }
11131124
11141125 tv.tv_sec = 0 ;
1126+ #ifdef REHLDS_FIXES
1127+ tv.tv_usec = 0.25 * 1000000 ;
1128+ #else
11151129 tv.tv_usec = 20 * 1000 ;
1130+ #endif
11161131
11171132 return select ((int )(number + 1 ), &fdset, NULL , NULL , net_sleepforever == 0 ? &tv : NULL );
11181133}
11191134
11201135#ifdef _WIN32
1121-
11221136DWORD WINAPI NET_ThreadMain (LPVOID lpThreadParameter)
1137+ #else
1138+ void * NET_ThreadMain (void *)
1139+ #endif // _WIN32
11231140{
11241141 while (true )
11251142 {
@@ -1130,6 +1147,14 @@ DWORD WINAPI NET_ThreadMain(LPVOID lpThreadParameter)
11301147 {
11311148 NET_ThreadLock ();
11321149
1150+ #ifdef REHLDS_FIXES
1151+ if (net_thread_terminated)
1152+ {
1153+ NET_ThreadUnlock ();
1154+ return 0 ;
1155+ }
1156+ #endif
1157+
11331158 bret = NET_QueuePacket ((netsrc_t )sock);
11341159 if (bret)
11351160 {
@@ -1163,31 +1188,40 @@ DWORD WINAPI NET_ThreadMain(LPVOID lpThreadParameter)
11631188
11641189 Sys_Sleep (1 );
11651190 }
1166-
11671191 return 0 ;
11681192}
11691193
1170- #endif // _WIN32
1171-
11721194void NET_StartThread ()
11731195{
11741196 if (use_thread)
11751197 {
11761198 if (!net_thread_initialized)
11771199 {
11781200 net_thread_initialized = TRUE ;
1201+ #ifdef REHLDS_FIXES
1202+ net_thread_terminated = false ;
1203+ #endif
11791204
11801205#ifdef _WIN32
11811206 InitializeCriticalSection (&net_cs);
11821207 hNetThread = CreateThread (0 , 0 , NET_ThreadMain, 0 , 0 , &dwNetThreadId);
11831208 if (!hNetThread)
11841209 {
11851210 DeleteCriticalSection (&net_cs);
1211+ #else
1212+ // In-line: There are several cases where mutex can go recursive in one thread.
1213+ pthread_mutexattr_t net_mutex_attr;
1214+ pthread_mutexattr_init (&net_mutex_attr);
1215+ pthread_mutexattr_settype (&net_mutex_attr, PTHREAD_MUTEX_RECURSIVE );
1216+ pthread_mutex_init (&net_mutex, &net_mutex_attr);
1217+ if (pthread_create (&hNetThread, nullptr , &NET_ThreadMain, nullptr ) != 0 )
1218+ {
1219+ pthread_mutex_destroy (&net_mutex);
1220+ #endif
11861221 net_thread_initialized = FALSE ;
11871222 use_thread = FALSE ;
11881223 Sys_Error (" %s: Couldn't initialize network thread, run without -netthread\n " , __func__);
11891224 }
1190- #endif // _WIN32
11911225 }
11921226 }
11931227}
@@ -1198,9 +1232,35 @@ void NET_StopThread()
11981232 {
11991233 if (net_thread_initialized)
12001234 {
1235+ #ifdef REHLDS_FIXES // Safe thread stopping.
1236+ NET_ThreadLock ();
1237+ net_thread_terminated = true ;
1238+ NET_ThreadUnlock ();
1239+ #endif // REHLDS_FIXES
1240+
12011241#ifdef _WIN32
1202- TerminateThread (hNetThread, 0 );
1242+
1243+ #ifdef REHLDS_FIXES
1244+ if (WaitForSingleObject (hNetThread, 0.5 * 1000 ) != WAIT_OBJECT_0 ) // Wait 0.5 second for thread to finish
1245+ #endif // REHLDS_FIXES
1246+ {
1247+ TerminateThread (hNetThread, 0 ); // Kill unresponsive thread.
1248+ }
12031249 DeleteCriticalSection (&net_cs);
1250+
1251+ #else // _WIN32
1252+ struct timespec ts;
1253+ if (clock_gettime (CLOCK_REALTIME , &ts) == -1 ) {
1254+ Sys_Error (" %s: CLOCK_REALTIME ERROR: %s" , __func__, NET_ErrorString (NET_GetLastError ()));
1255+ }
1256+ ts.tv_nsec += 0.5 * 1000000000 ; // Wait 0.5 second for thread to finish
1257+
1258+ if (pthread_timedjoin_np (hNetThread, nullptr , &ts) != 0 )
1259+ {
1260+ pthread_cancel (hNetThread); // Kill unresponsive thread.
1261+ pthread_join (hNetThread, nullptr );
1262+ }
1263+ pthread_mutex_destroy (&net_mutex);
12041264#endif // _WIN32
12051265 net_thread_initialized = FALSE ;
12061266 }
@@ -2013,9 +2073,15 @@ void NET_Init()
20132073 Cvar_RegisterVariable (&net_graphpos);
20142074
20152075 if (COM_CheckParm (" -netthread" ))
2076+ #if defined(REHLDS_FIXES) || defined(_WIN32) // -netthread will work either on windows or on fixed linux build.
20162077 use_thread = TRUE ;
2078+ #else
2079+ use_thread = FALSE ;
2080+ #endif
20172081
2018- if (COM_CheckParm (" -netsleep" ))
2082+ #ifndef REHLDS_FIXES
2083+ if (COM_CheckParm (" -netsleep" )) // Sleeping forever is useless.
2084+ #endif
20192085 net_sleepforever = 0 ;
20202086
20212087#ifdef _WIN32
0 commit comments