1 /*****************************************************************************
2  * Copyright (C) 2013-2020 MulticoreWare, Inc
3  *
4  * Authors: Steve Borho <steve@borho.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
19  *
20  * This program is also available under a commercial proprietary license.
21  * For more information, contact us at license @ x265.com
22  *****************************************************************************/
23 
24 #include "threading.h"
25 
26 #if defined(_WIN32) && (_WIN32_WINNT < 0x0600) // _WIN32_WINNT_VISTA
27 
28 namespace X265_NS {
29 /* Mimic CONDITION_VARIABLE functions only supported on Vista+ */
30 
cond_init(ConditionVariable * cond)31 int WINAPI cond_init(ConditionVariable *cond)
32 { // InitializeConditionVariable
33     cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
34     if (!cond->semaphore)
35         return -1;
36     cond->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
37     if (!cond->waitersDone)
38         return -1;
39 
40     InitializeCriticalSection(&cond->waiterCountMutex);
41     InitializeCriticalSection(&cond->broadcastMutex);
42     cond->waiterCount = 0;
43     cond->bIsBroadcast = false;
44 
45     return 0;
46 }
47 
cond_broadcast(ConditionVariable * cond)48 void WINAPI cond_broadcast(ConditionVariable *cond)
49 { // WakeAllConditionVariable
50     EnterCriticalSection(&cond->broadcastMutex);
51     EnterCriticalSection(&cond->waiterCountMutex);
52     int haveWaiter = 0;
53 
54     if (cond->waiterCount)
55     {
56         cond->bIsBroadcast = 1;
57         haveWaiter = 1;
58     }
59 
60     if (haveWaiter)
61     {
62         ReleaseSemaphore(cond->semaphore, cond->waiterCount, NULL);
63         LeaveCriticalSection(&cond->waiterCountMutex);
64         WaitForSingleObject(cond->waitersDone, INFINITE);
65         cond->bIsBroadcast = 0;
66     }
67     else
68         LeaveCriticalSection(&cond->waiterCountMutex);
69 
70     LeaveCriticalSection(&cond->broadcastMutex);
71 }
72 
cond_signal(ConditionVariable * cond)73 void WINAPI cond_signal(ConditionVariable *cond)
74 { // WakeConditionVariable
75     EnterCriticalSection(&cond->broadcastMutex);
76     EnterCriticalSection(&cond->waiterCountMutex);
77     int haveWaiter = cond->waiterCount;
78     LeaveCriticalSection(&cond->waiterCountMutex);
79 
80     if (haveWaiter)
81     {
82         ReleaseSemaphore(cond->semaphore, 1, NULL);
83         WaitForSingleObject(cond->waitersDone, INFINITE);
84     }
85 
86     LeaveCriticalSection(&cond->broadcastMutex);
87 }
88 
cond_wait(ConditionVariable * cond,CRITICAL_SECTION * mutex,DWORD wait)89 BOOL WINAPI cond_wait(ConditionVariable *cond, CRITICAL_SECTION *mutex, DWORD wait)
90 { // SleepConditionVariableCS
91     EnterCriticalSection(&cond->broadcastMutex);
92     EnterCriticalSection(&cond->waiterCountMutex);
93     cond->waiterCount++;
94     LeaveCriticalSection(&cond->waiterCountMutex);
95     LeaveCriticalSection(&cond->broadcastMutex);
96 
97     // unlock the external mutex
98     LeaveCriticalSection(mutex);
99     BOOL ret = WaitForSingleObject(cond->semaphore, wait);
100 
101     EnterCriticalSection(&cond->waiterCountMutex);
102     cond->waiterCount--;
103     int last_waiter = !cond->waiterCount || !cond->bIsBroadcast;
104     LeaveCriticalSection(&cond->waiterCountMutex);
105 
106     if (last_waiter)
107         SetEvent(cond->waitersDone);
108 
109     // lock the external mutex
110     EnterCriticalSection(mutex);
111 
112     // returns false on timeout or error
113     return ret;
114 }
115 
116 /* Native CONDITION_VARIABLE instances are not freed, so this is a special case */
cond_destroy(ConditionVariable * cond)117 void cond_destroy(ConditionVariable *cond)
118 {
119     CloseHandle(cond->semaphore);
120     CloseHandle(cond->waitersDone);
121     DeleteCriticalSection(&cond->broadcastMutex);
122     DeleteCriticalSection(&cond->waiterCountMutex);
123 }
124 } // namespace X265_NS
125 
126 #elif defined(_MSC_VER)
127 
128 namespace { int _avoid_linker_warnings = 0; }
129 
130 #endif // _WIN32_WINNT <= _WIN32_WINNT_WINXP
131